C++内存管理07 GCC std::alloc 运行模式解读

GCC std::alloc 运行模式解读

首先看如下图,这个图是侯捷老师画的,我向他致敬
在这里插入图片描述
前面几章我写的内存管理器,一次只能管理一个内存链表。在这里alloc将会管理16种不同的链表。Free_list[16],其中管理关系如下规则:
0-8
1-16
2-24
3-32

14-120
15-128

运行模式解释情景1:
首先要声明一点,在这里alloc会自动将用户传入的内存大小和自身设定的大小对齐,比如用户需要6个字节,则对齐就为8个字节,需要30个就对齐为32个字节。
假设客户要32个字节,alloc在这里就会分配32*20*2,其中20是分配的个数,至于为什么是20,我不得而知,侯捷也不知道,也许是团队的经验值吧,不多也不少,至于后面的2是战备池(作用后面情景2再讲)
所以现在一下子malloc就得到了1280个字节,只带了上下cookie,其中640个字节也就是20*32,分配一个给用户,剩余19个,如果这19个用完就从战备池继续使用,战备池用完就继续malloc重复此操作。
情景2:
假设32个字节的就用了一个,然后来了另外的一个容器,比如需要64个字节,首先free_list[3]为空,没有挂在链表,先看看战备池,它有640个字节,那么它可以分为64*10,10个,然后就把free_list[3]挂载到战备池的开始地址。
情景3:
现在又出现了一个容器需要96个字节,一看战备池已经被用完了,free_list[11]为空,那么就malloc,96*20*2 其中一半为战备池,具体操作过程回到情景1

接下来直接看图:
在这里插入图片描述
这张图可以看到有16根指针,将来分别指向不同大小的内存。
在这里插入图片描述
用户需要32个字节,则链表的标记应该为:n = 32/8 -1,则为3;

首先检查free_list[3]是否有挂指向内存的指针,一看没有,则使用malloc申请内存。在这里申请了1280字节,其中640个字节是备用的。还有640字节,分为了20个32字节大小的块,最前面的一个给了用户,剩下的19个挂在了free_list[3]上。
注意分配的大小:

nMax = 32*20*2 + RoundUp(0>>4)

和这个和当前已经分配的内存大小有关。
在这里插入图片描述
接下来用户有需要64字节的空间,同理先计算链表标记,n = 64/8 - 1,则为7;

此时备用池为640.
已经分配1280

先检查free_list[7]有没有指向内存的指针,一看没有,则需要malloc,但一检查,备用池不为空(剩余640个字节),于是先用备用池进行分配。

在这里,不管备用池大小为多少,都最多只能分配用户大小的20倍。640/64 = 10;则可以分为10个;然后挂在free_list[7]上。

此时备用池为0.
已经分配1280

在这里插入图片描述
现在用户又有了新的申请,大小为96字节,同理先算标记:n = 96/8 - 1,则为11,查看得free_list[7]没有指向内存的指针,所以需要充值内存,但充值之前需要看备用池有没有,因为此时备用池已经为0,所以需要使用malloc来申请内存,大小为:96*20*2 +RoundUp(),调整边界,最后得到申请的内存为4000。20个96字节大小的块,第一块给了用户,剩余的19块,free_list[11]去接它。

此时已经分配了1280的字节。
注意分配大小:

nMax = 96*20*2 + RoundUp(1280>>4)

RoundUp(1280>>4):先将1280/16为80,然后再调整为8的倍数,而80干好为8的倍数,所以有如下计算过程:
3840+80 = 3920,
3920-96*20 = 2000
此时备用池为2000.
已经分配1280
此时总申请量为5200

在这里插入图片描述
接着客户又需要88大小的内存,n = 88/8 - 1,为free_list[10];

由于备用池有余量(2000),则划分为20*88 = 1760,然后挂在free_list[10]上。

则此时备用池为240
在这里插入图片描述
这张图是连续分配了三个88的效果,绿色部分表示已经分配出去了。

在这里插入图片描述
此时用户又需要大小为8字节的内存大小,n = 8/8 - 1,则为free_list[0],一看free_list[0]上为空,然后充值内存,先看备用池(余量240),那就给它分配:20*8 = 160,然后挂在free_list[0]上。

则此时备用池为240-160 = 80.

在这里插入图片描述
此时用户需要104字节大小的内存,n = 104/8 - 1 = 12;查看free_list[13]为空,则充值内存,的备用池为80,我靠不够啊,这里80就成了内存碎片,但我不能浪费啊,于是前辈们就想了一个办法,那就把它挂在其它链表呗,那我就算算挂在哪合适:n = 80/8 - 1,则为9,那就给free_list[9],这样就避免了浪费空间,等到需要free_list[9]时就分配出去了。

内存碎片处理完之后,现在继续走主线任务:

104*20*2 + RoundUp(5200>>4)

这里的5200是目前已经分配的大小。

RoundUp(5200>>4)) :
5200/16 = 325,然后将325调整为8的边界,325/8 = 40.625==>41,
则调整为41*8 = 328
则最终大小为:

104*20*2 + 328 = 4488

则此时总共分配了:5200+4488 = 9688
备用池为:4488 - 104*20 = 2408

在这里插入图片描述
用户需要112字节的内存,计算得 n = 112/8 -1 = 13,查看free_list[13]为空
则如法炮制,得到如下结果:
已经申请量:9688
备用池:2408-112*20 = 168
在这里插入图片描述
接下来用户又要48字节的空间,方法一样,得到free_list[5]为空,则从备用池取,一看为168,最多也就分配3个,那就三个吧,一个给了用户,另外两个挂在free_list[5]上。
此时备用池为168-48*3 = 24

在这里插入图片描述
方法和之前一样还是先处理内存碎片24字节。不过特殊的地方是就近取内存,余下的加到备用池。
在这里插入图片描述
注意备用池大小为11*8 - 72 = 16
在这里插入图片描述
注意free_list[15]为空。如果你把我之前的都看懂了,那么这张应该不是问题。看不懂的可以留言。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

发如雪-ty

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值