江西省城乡建设厅网站,网站免费空间,大连58同城招聘网最新招聘,嘉兴企业网站https://zhuanlan.zhihu.com/p/693267319 1 双层内存配置器
SGI设计了两层的配置器#xff0c;也就是第一级配置器和第二级配置器。同时为了自由选择#xff0c;STL又规定了 __USE_MALLOC 宏#xff0c;如果它存在则直接调用第一级配置器#xff0c;不然则直接调用第二级配… https://zhuanlan.zhihu.com/p/693267319 1 双层内存配置器
SGI设计了两层的配置器也就是第一级配置器和第二级配置器。同时为了自由选择STL又规定了 __USE_MALLOC 宏如果它存在则直接调用第一级配置器不然则直接调用第二级配置器。SGI未定义该宏也就是说默认使用第二级配置器。
1.1 一级内存配置器
直接调用malloc和free来配置释放内存简单明了。
templateint Inst
class __MallocAllocTemplate //一级空间配置器
{typedef void (*OOM_HANDLER)();
private://these funs below are used for OOM situations//OOM out of memorystatic void* OOM_Malloc(size_t n); //functionstatic void* OOM_Realloc(void *p, size_t newSZ); //functionstatic OOM_HANDLER OOM_Handler; //function pointerpublic:static void* Allocate(size_t n){void* ret malloc(n);if (ret NULL)ret OOM_Malloc(n);return ret;}static void Deallocate(void* p, size_t n){free(p);}static void* Reallocate(void* p, size_t oldSZ, size_t newSZ){void* ret realloc(p, newSZ);if (ret NULL)ret OOM_Realloc(p, newSZ);return ret;}//static void (* set_malloc_handler(void (*f)()))()//参数和返回值都是函数指针void (*)()static OOM_HANDLER SetMallocHandler(OOM_HANDLER f){OOM_HANDLER old OOM_Handler;OOM_Handler f;return old;}
};//让函数指针为空
templateint Inst
void (*__MallocAllocTemplateInst::OOM_Handler)() NULL;templateint Inst
void* __MallocAllocTemplateInst::OOM_Malloc(size_t n)
{void* ret NULL;void(*myHandler)() NULL;for (;;){myHandler OOM_Handler;if (myHandler NULL)throw bad_alloc();(*myHandler)();ret malloc(n);if (ret ! NULL)return ret;}
}templateint Inst
void* __MallocAllocTemplateInst::OOM_Realloc(void* p, size_t newSZ)
{void* ret NULL;void(*myHandler)() NULL;for (;;){myHandler OOM_Handler;if (myHandler NULL)throw bad_alloc();(*myHandler)();ret realloc(p, newSZ);if (ret ! NULL)return ret;}
}typedef __MallocAllocTemplate0 MallocAlloc; //一级空间配置重命名1.2 二级内存配置器
1.如果用户需要的区块大于128则直接调用第一级空间配置器 2.如果用户需要的区块大于128则到自由链表中去找
如果自由链表有则直接去取走不然则需要装填自由链表Refill
1.2.1 自由链表 自由链表是一个指针数组它的数组大小为16每个数组元素代表所挂的区块大小比如free _ list[0]代表下面挂的是8bytes的区块free _ list[1]代表下面挂的是16bytes的区块…….依次类推直到free _ list[15]代表下面挂的是128bytes的区块
同时我们还有一个被称为内存池地方以start _ free和 end _ free记录其大小用于保存未被挂在自由链表的区块它和自由链表构成了伙伴系统。
1.2.2 工作原理
如果用户需要是一块n字节的区块且n 128调用第二级配置器此时Refill填充是这样的
系统会自动将n字节扩展到8的倍数再将RoundUPn传给Refill。用户需要n字节且自由链表中没有因此系统会向内存池申请nobjs * n大小的内存块默认nobjs20如果内存池大于 nobjs * n那么直接从内存池中取出如果内存池小于nobjs * n但是比一块大小n要大那么此时将内存最大可分配的块数给自由链表并且更新nobjs为最大分配块数x x nobjs如果内存池连一个区块的大小n都无法提供那么首先先将内存池残余的零头给挂在自由链表上然后向系统heap申请空间申请成功则返回申请失败则到自己的自由链表中看看还有没有可用区块返回如果连自由链表都没了最后会调用一级配置器。
3 自定义内存配置器
// TODO:为vector写一个内存配置器当空间大于1000时直接从堆分配内存#include memory
#include vector
#include iostream// 自定义内存配置器
template typename T
class CustomAllocator : public std::allocatorT {
public:// 分配内存T* allocate(std::size_t n) {if (n * sizeof(T) 1000) {// 大于1000字节时使用堆分配return static_castT*(::operator new(n * sizeof(T)));} else {// 小于或等于1000字节时使用默认分配return std::allocatorT::allocate(n);}}// 释放内存void deallocate(T* p, std::size_t n) {if (n * sizeof(T) 1000) {// 大于1000字节时使用堆释放::operator delete(p);} else {// 小于或等于1000字节时使用默认释放std::allocatorT::deallocate(p, n);}}
};int main() {// 使用自定义内存配置器的vectorstd::vectorint, CustomAllocatorint vec;vec.push_back(1); // 应该使用默认分配方式通常很小vec.push_back(2); // 同上vec.resize(1024); // 应该使用堆分配方式因为1024 * sizeof(int) 1000vec.resize(1); // 应该再次使用默认分配方式因为1 * sizeof(int) 1000return 0;
}