CPP内存管理(二)

本文详细探讨了VC6.0malloc、G2.9和G4.9版本的内存分配器std::alloc以及__pool_alloc的工作原理,涉及内存申请不同大小的情况,以及系统内存不足时的处理策略,同时指出内存管理中的两个主要问题:空间未充分利用和碎片回收的复杂性。
摘要由CSDN通过智能技术生成

VC6.0 malloc

在这里插入图片描述
VC6的malloc函数分配的内存除了申请的空间之外,还有cookie以及一些额外的overhead。如果大量调用malloc会造成很大浪费。
在这里插入图片描述
VC6.0的allocate()函数只是对malloc的二次封装,并没有做什么很特殊的操作,它是以类型字节长度为单位分配内存的,上图就分配了512个int类型空间。
BC5的allocate( )函数和VC6.0本质一样。

G2.9 allocator

在这里插入图片描述

G2.9 std::alloc

gcc2.9版本如图所示,但是实际中却没有包含使用上图的allocator(),而是使用下图的std::alloc
在这里插入图片描述

上图的容器使用Alloc可见,实际的分配器使用的是一个alloc的类,该类分配内存是以字节为单位的,而不是以对象为单位。可以使用alloc::allocate(512),这路分配的是512字节,而不是512个对象。

G2.9std::alloc VS G4.9__pool_alloc

gcc4.9版本,2.9版本的allocate不属于正式使用的版本了,而使用__pool_alloc,2.9版本的allocate和4.9版本的__pool_alloc效果相同。在这里插入图片描述
测试发现:__gun_cxx::__pool_alloc分配3个8B的double,相距08H,证明不带cookie
而std::allocator的带cookie。

std::alloc解读

在这里插入图片描述
std::alloc使用一个带有16个元素为指针的数组,数组不同的元素管理不同的区块,#0表示8个字节的大小,#1表示16个字节的大小,以此类推。当分配的时候不足会按照8字节向上取整,如需要一个6字节会分配8个字节的大小。若超过128B的话std::alloc会直接调用malloc给用户分配空间。

申请32B

pool:预留的空间,方便用户后续需要时不需要重新申请空间。
RoundUp:实现8字节对齐.例如传入13,传出的就是16. 0>>4表示右移4位
嵌入式指针:将每一块的前四个字节用作指针连接下一块可用的内存块,可以节省空间。(空闲的空间未分配,所以使用前4个字节无可厚非;已分配的内存会将地址返回给用户,所以不需要使用这个指针。

假如现在需要申请32B的大小,先判断#3对应的指针域为空,且pool为空, std::alloc会申请32202+RoundUp并将32*20的空间分成20块然后分配第一块,并将后续19块挂到#3上作为后续分配。后续640B会作为pool来为后续使用。

申请64B

pool:只要能提供1~20个就可以使用pool

申请64B的大小,发现#7为空,但是此时pool不为空,且这个pool可以提供10个(在1~20之间)此时将原来的pool作为这个64B的挂到#7上,并分配一块给用户,分配之后pool置为0。这样做的好处是可以减少使用malloc的次数,因为若没有pool,此时需要重新使用malloc,这个malloc的空间带cookie,浪费空间。
在这里插入图片描述

申请96B

由于pool没有剩余的空间,所以会重新malloc,96202+RoundUp,其余同上。
在这里插入图片描述

申请88B

申请88B的大小,发现#10为空,但是此时pool不为空,且这个pool可以提供,但是这时候pool可以提供不止20个,编译器也只会提供最多20个,并从中分配一块给用户,此时pool剩余2000-88*20=240。
在这里插入图片描述

继续申请3块88B

申请88B的大小,发现#10不为空,直接从链表上摘下一块分配给用户。
在这里插入图片描述

申请8B

申请8B的大小,发现#0为空,但是此时pool不为空,且这个pool可以提供,但是这时候pool可以提供不止20个,编译器也只会提供最多20个,并从中分配一块给用户,此时pool剩余240-8*20=80。
在这里插入图片描述

申请104B

此时pool提供的余量不够供应,先将pool的剩余空间(内部碎片)挂到#9上。再利用malloc申请104202+RoundUp,分配一块给用户。
在这里插入图片描述

申请112B

申请112B的大小,发现#13为空,但是此时pool不为空,且这个pool可以提供,这时候pool可以提供不止20个,但是编译器也只会提供最多20个,并从中分配一块给用户,此时pool剩余2408-112*20=168。
在这里插入图片描述

申请48B

申请48B的大小,发现#5为空,但是此时pool不为空,且这个pool可以提供3个(1~20之间),并从中分配一块给用户,此时pool剩余168-48*3=24。
在这里插入图片描述

系统可分配的内存不足,如何处理

申请72B

申请72B的大小,发现#8为空,但是此时pool不为空,但是这个pool又不足以供应一个,此时进行碎片处理,将pool剩余的24B挂到#2上。然后需要malloc对应的大小,但是此时若系统的heap大小为10000,而此时已分配的为9688,此时再向重新malloc会失败,此时会和后边的链表借,因为#8后面的#9此时满足,从中切除72B分配给用户,此时pool剩余80-72=8B。剩余的72B则返回给用户。
在这里插入图片描述
再次申请72B的大小,发现pool不足以分配,将pool的内存碎片处理pool=0,并查看#9发现已经没用可用的,继续查看#10,发现有可用,从中切除72B分配给用户,此时pool剩余88-72=16。

申请120B

申请120B,此时已经无法找到合适的借用
在这里插入图片描述

检讨

在这里插入图片描述

检讨一

alloc已经分配出去的空间,但是此时没有被有效使用,但是回收起来很麻烦。因为在未分配的空间是通过指针串起来的,系统可能经过多次的申请和释放(这里释放并不是指给OS回收,而是返回给这个std::allloc,这里OS并没有回收分配的内存)这个时候空间可能早就不是连续的了,如下图,回收难度很大。
在这里插入图片描述

检讨二

像上面的例子剩余312B,可以将失败的那次通过一直折半折半再折半,最终获取<=312可以满足,实现起来不是很难,但是在GCC中并没有采取任何做法。

  • 26
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值