57、什么是内存池,如何实现

内存池(Memory Pool) 是一种内存分配方式。通常我们习惯直接使用new、malloc 等申请内存,这 样做的缺点在于:由于所申请内存块的大小不定,当频繁使用时会造成大量的内存碎片并进而降低性 能。内存池则是在真正使用内存之前,先申请分配一定数量的、大小相等(一般情况下)的内存块留作备 用。当有新的内存需求时,就从内存池中分出一部分内存块, 若内存块不够再继续申请新的内存。这样 做的一个显著优点是尽量避免了内存碎片,使得内存分配效率得到提升。

这里简单描述一下《STL源码剖析》中的内存池实现机制:

allocate包装malloc,deallocate包装free

一般是一次20*2个的申请,先用一半,留着一半,为什么也没个说法,侯捷在STL那边书里说好像是 C++委员会成员认为20是个比较好的数字,既不大也不小

1. 首先客户端会调用malloc()配置一定数量的区块(固定大小的内存块,通常为8的倍数),假设40 个32bytes的区块,其中20个区块(一半)给程序实际使用,1个区块交出,另外19个处于维护状 态。剩余20个(一半)留给内存池,此时一共有(20*32byte)

2. 客户端之后有有内存需求,想申请(20*64bytes)的空间,这时内存池只有(20*32bytes),就 先将(10*64bytes)个区块返回,1个区块交出,另外9个处于维护状态,此时内存池空空如也

3. 接下来如果客户端还有内存需求,就必须再调用malloc()配置空间,此时新申请的区块数量会增加 一个随着配置次数越来越大的附加量,同样一半提供程序使用,另一半留给内存池。申请内存的时 候用永远是先看内存池有无剩余,有的话就用上,然后挂在0-15号某一条链表上,要不然就重新 申请。

4. 如果整个堆的空间都不够了,就会在原先已经分配区块中寻找能满足当前需求的区块数量,能满足 就返回,不能满足就向客户端报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表示 24bytes。。。。而15 表 示 16* 8 = 128bytes,如果在申请时并不是8的倍数,那就找刚好能满足内存大小的那个位置。比如想 申请 12,那就是找16了,想申请 20 ,那就找 24 了

但是现在GC4.9及其之后 也还有,变成_pool_alloc这个名字了,不再是默认的了,你需要自己去指定它 可以自己指定,比如说vector<string,__gnu_cxx::pool_alloc> vec;这样来使用它,现在用的又回到以前 那种对malloc和free的包装形式了

原文地址:https://www.cnblogs.com/crbhf/p/15087525.html