3.什么是内存池,如何实现
内存池(Memory Pool) 是一种内存分配方式。通常我们习惯直接使用new、malloc 等申请内存,这样做的缺点在于:由于所申请内存块的大小不定,当频繁使用时会造成大量的内存碎片并进而降低性能。内存池则是在真正使用内存之前,先申请分配一定数量的、大小相等(一般情况下)的内存块留作备用。当有新的内存需求时,就从内存池中分出一部分内存块, 若内存块不够再继续申请新的内存。这样做的一个显著优点是尽量避免了内存碎片,使得内存分配效率得到提升。
这里简单描述一下《STL源码剖析》中的内存池实现机制:
allocate 包装 malloc,deallocate包装free
一般是一次20*2个的申请,先用一半,留着一半,为什么也没个说法,侯捷在STL那边书里说好像是C++委员会成员认为20是个比较好的数字,既不大也不小。
- 首先客户端会调用malloc()配置一定数量的区块(固定大小的内存块,通常为8的倍数),假设40个32bytes的区块,其中20个区块(一半)给程序实际使用,1个区块交出,另外19个处于维护状态。剩余20个(一半)留给内存池,此时一共有(20*32byte)
- 客户端之后有有内存需求,想申请(20*64bytes)的空间,这时内存池只有(20*32bytes),就先将(10*64bytes)个区块返回,1个区块交出,另外9个处于维护状态,此时内存池空空如也.
- 接下来如果客户端还有内存需求,就必须再调用malloc()配置空间,此时新申请的区块数量会增加一个随着配置次数越来越大的附加量,同样一半提供程序使用,另一半留给内存池。申请内存的时候用永远是先看内存池有无剩余,有的话就用上,然后挂在0-15号某一条链表上,要不然就重新申请。
- 如果整个堆的空间都不够了,就会在原先已经分配区块中寻找能满足当前需求的区块数量,能满足就返回,不能满足就向客户端报bad_alloc异常
allocator就是用来分配内存的,最重要的两个函数是allocate和deallocate,就是用来申请内存和回收内存的,外部(一般指容器)调用的时候只需要知道这些就够了。
内部实现,目前的所有编译器都是直接调用的::operator new()和::operator delete(),说白了就是和直接使用new运算符的效果是一样的,所以老师说它们都没做任何特殊处理。
其实最开始GC2.9之前
new和 operator new 的区别:new 是个运算符,编辑器会调用 operator new(0)
operator new()里面有调用malloc的操作,那同样的 operator delete()里面有调用的free的操作
GC2.9下的alloc函数的一个比较好的分配器的实现规则如下:
维护一条0-15号的一共16条链表,其中 0 号表示8 bytes ,1 号表示 16 bytes,2 号表示 24 bytes。。。。而15 号表示 16* 8 = 128 bytes。
如果在申请内存时,申请内存的大小并不是8的倍数(比如2、4、7、9、18这样不是8的倍数),那就找刚好能满足内存大小的链表。比如想申请 12 个大小,那就按照 16 来处理,也就是找 1 号链表了;想申请 20 ,距离它最近的就是 24 了,那就找 2 号链表。
只许比所要申请的内容大,不许小!
但是现在GC4.9及其之后 也还有 alloc 函数,只不过已经变成_pool_alloc这个名字了,名字已经改了,也不再是默认的了。
你需要自己手动去指定它可以自己指定,比如
vector<string,__gnu_cxx::pool_alloc<string>> vec;
标签:20,实现,申请,如何,内存,operator,new,区块
From: https://www.cnblogs.com/codemagiciant/p/17601854.html