我正在研究一种用于学习记忆管理的tcmalloc。
但还有一部分我想不出来。
使用buddy algorithmn时,分割或合并blok时如何管理头块我的意思是,当你合并两个区块时,你不再需要两个标题了,那又怎样?你只是释放了记忆?如果我没有错的话,你不能在两块之间释放内存空间。
所以欢迎任何帮助或链接^^
谢谢!
编辑:
在和一些人交谈之后,我发现我需要在另一个内存区域管理块头。是吗?我该怎么做?

最佳答案

我认为您可能会感到困惑的地方是,在现有内存头存储的地方改写内存没有什么问题。事实上,除了在拆分块时动态插入新的头之外,当您通过合并合并合并块时,还希望有效地实现这一点。
因此,如果我们设想一个简化的示例,其中order-0块是64字节,而最大的order-3块是256字节,那么我们从256字节order-2块开始,如下所示:

[nil<-header1->nil][data1 ...............................]

其中data1是客户机可以使用的内存,客户机请求根据需要覆盖内存作为一个基本示例,我们还假设您使用8字节的头来进行64位对齐,它存储到相邻的上一个/下一个块的整数偏移量,以及一个标志,指示使用了哪些块及其大小(如果一个块有一个下一个/上一个偏移量,使其相邻并匹配相同的大小,则该块是一个伙伴)。最初,这些值可以是-1,表示没有可用的相邻块。
另一种查看初始256字节的order-2块的方法是需要有足够的空间来容纳4个order-0块。所以块的总内存大小应该是256+4*8字节,或者288字节。
现在假设客户机请求分配128个字节。在这种情况下,我们需要将256字节的order-2块分成两个order-1块,将它们的大小减半。在这个过程中,我们可以在中间插入一个新的头,在data1开始的地址后面128字节。
[nil<-header1->header2][data1........[header1<-header2->nil][data2]........]

这个新的header2应该有一个-1的next偏移量,以表示它在列表的末尾,其好友的前一个偏移量指向header1header1还应该更新它的下一个偏移量以指向header2,并且我们应该使两者的大小都为128字节(是块分割前最初存储的header1大小的一半)。
然后,我们可以返回指向data1的指针,以便客户端按其意愿写入,还可以将header1标记为正在使用。
现在假设客户机请求释放该块。在这种情况下,我们可以从他传入的从data1header1的内存地址中减去8个字节。我们还可以从header1中看到,它的邻居header2当前未使用,而其大小与header1相同,因此它是适合合并的伙伴。所以我们就可以合并了。
这个过程很简单。header1's下一个偏移量简单地用header2's下一个偏移量(即-1)覆盖,其大小加倍我们仍然会让header2数据在内存中徘徊,直到用户覆盖它(除非它是calloc样式的操作,我们自己编写0来覆盖它)然而,它只是一个在内存中漂浮的挥之不去的工件,现在打算被重写。
[nil<-header1->nil][data1 ...............................]

这描述了一个相当基本的实现,我只讨论了如何处理拆分和合并的一种可能性。您还可以获得花哨的标题并将其存储在一个单独的内存空间中,但这通常会增加一些处理开销,比如通过某种搜索从指针获取适当的标题信息使用最小的0阶块(主要是通过避免对齐要求)可以减少内存开销,但是要使速度更快会有点困难。当头文件存储在同一个地方时,我们可以做一些基本的事情,比如简单的减法运算来获取头文件的内容。

09-07 16:13