为什么需要两级空间适配器? 因为我们如果频繁的再堆上面申请内存释放内存,就会在堆上面造成很多的外部碎片,造成空间浪费,每次都要调用malloc、free函数,降低空间利用率。
一级空间适配器: 当申请内存>128bytes的时候就用一级空间适配器。(malloc、free、realloc等方法)
二级空间适配器:当申请的内存 <=128bytes的时候就用二级空间适配器。默认STL使用二级。
二级空间适配器的工作原理:
1、维护16条链表,分别是0-15号链表,最小8字节,以8字节逐渐递增,最大128字节,你传入一个字节参数,表示你需要多大的内存,会自动帮你校对到第几号链表(如需要13bytes空间,我们会给它分配16bytes大小),在找到第n个链表后查看链表是否为空,如果不为空直接从对应的free lit中拔出,将已经拨出的指针向后移动一位。
2、对应的fe lst为空,先看其内存池是不是空时,如果内存池不为空:
(1)先检验它剩余空间是否够20个节点大小(即所需内存大小提升后)20),若足够则直接从内存池中拿出20个节点大小空间,将其中一个分配给用户使用,另外19个当作自由链表中的区块挂在相应的fre .lst下,这样下次再有相同大小的内存需求时,可直接拨出。
(2))如果不够20个节点大小,则看它是否能满足/1个节点大小,如果够的话则直接拿出一个分配给用户,然后从剩余的空间中分配尽可能多的节点挂在相应的ire ist中。
(3)如果连一个节点内存都不能满足的话,则将内存池中剩余的空间挂在相应的fe. lit中(找到相应的fre.lit),然后再给内存池申请内存,转到3。
3、内存池为空,申请内存此时二级空间配置器会使用malc)从heap上申请内存,(一次所申请的内存大小为2所需节点内存大小(提升后)'20+一段额外空间),申请A0块,一半拿来用,一半放内存池中。4、mallc没有成功在第三种情况下,如果malloc失败了,说明heap上没有足够空间分配给我们了,这时,二级空间配置器会从比所需节点空间大的fre lst中一一搜索,从比它所需节点空间大的fre list中拔除一个节点来使用。如果这也没找到,说明比其大的fre lit中都没有自由区块了,那就要调用一级适配器了。
释放时调用deallocate()函数,若释放的n>128,则调用一级空间配置器,否则就直接将内存块挂上自由链表的合适位置。
STL二级空间配置器虽然解决了外部碎片与提高了效率,但它同时增加了一些缺点:
1.因为自由链表的管理问题,它会把我们需求的内存块自动提升为8的倍数,这时若你需要1个字节,它会给你8个字节,即浪费了7个字节,所以它又引入了内部碎片的问题,若相似情况出现很多次,就会造成很多内部碎片;
2.二级空间配置器是在堆上申清大块的狭义内存池,然后用自由链表管理,供现在使用,在程序执行过程中,它将申请的内存一块一块都挂在自由链表上,即不会还给操作系统,并且它的实现中所有成员全是静态的,所以它申请的所有内存只有在进程结束才会释放内存,还给操作系统,由此带来的问题有∶
1.即我不断的开辟小块内存,最后整个堆上的空间都被挂在自由链表上,若我想开辟大块内存就会失败;
2若自由链表上挂很多内存块没有被使用,当前进程又占着内存不释放,这时别的进程在堆上申请不到空间,也不可以使用当前进程的空闲内存,由此就会引发多种问题。