动态内存分配

时间:2015-05-05 16:40:06

标签: c malloc dynamic-memory-allocation

malloc()如何存储元数据?

void* p;
void* q;
p = malloc(sizeof(char));
q = malloc(sizeof(int));

我知道返回值p [0]指向已分配的内存块的开始,

比迭代和打印

p [-1],p [-2] .... q [-1],q [-2] ....

或p [1],p [2],p [3],p [4] .... 或q [1],q [2],q [3],q [4] ....

我发现一些值可以帮助malloc()存储我无法理解的数据 确切地说,元数据意味着什么..我只知道其中一些是块大小,对于下一个空闲块的地址,但我无法在网上找到

拜托,你能否详细解释一下这些价值?

4 个答案:

答案 0 :(得分:3)

此元数据的工作原理和使用方式完全取决于libc中的内存管理。以下是一些有用的文章,可以帮助您入门:

其中每一项都有不同的目标,益处和可能的不足。例如,您可能担心可能的堆溢出问题和保护。这可能导致一种选择。也许您正在寻找更好的片段管理。这可能会导致选择Doug Lee的malloc。您确实需要指定您正在使用的库或研究它们以了解元数据如何用于维护箱柜,合并无调整区域等。

答案 1 :(得分:0)

在您的示例中访问p[-1]等是违法的。结果将是未定义的,可能会导致内存损坏或分段错误。一般来说,你根本无法控制malloc()或者有关它正在做什么的信息。

那就是说,一些malloc()"替换"图书馆将为您提供更精细的控制或信息 - 您将这些链接链接到您的二进制文件"顶部"系统malloc()。

答案 2 :(得分:0)

C标准没有规定malloc如何存储其元数据(或者即使它具有可访问的元数据);因此,元数据格式和位置是依赖于实现的。因此,可移植代码必须永远不会尝试访问或解析元数据。

某些malloc实现作为扩展提供了malloc_usable_sizemalloc_size等函数,它们可以告诉您已分配块的大小。虽然这些功能的存在也取决于实现,但它们至少是可靠且正确的方式来获取所需信息(如果它们存在)。

答案 3 :(得分:0)

David Hoelzer有一个很好的答案,但我想更多地跟进它:

malloc的“元数据”是100%实现驱动的。以下是我编写或使用的一些实现的快速概述:

  • 元数据存储“下一个”块指针。
  • 它存储金丝雀值,以确保您没有通过块的结尾
  • 根本没有元数据,因为所有块都是相同的大小,并且它们被放置在堆栈中以允许O(1)访问 - 单元分配器。在这种情况下,你会从相邻的块中获取内存。
  • 数据存储下一个块ptr,prev块ptr,对齐ID,块大小以及一个标识符,该标识符告诉内存调试器确切的分配位置。对于泄漏跟踪非常有用。
  • 它会触及上一个块的信息,因为数据存储在块的尾部而不是头部......

或混合搭配以上所有内容。在任何情况下,读取mem[-1]都是一个坏主意,在某些情况下(思考嵌入式系统),如果所述读取恰好超出当前内存页面并进入禁止状态,则确实可能仅在读取时导致段故障记忆区。

根据OP

更新

我描述的第四种方案是每个块具有相当多的信息 - 16字节的信息并不罕见,因为该大小不会抛弃常见的对齐方案。它将包含一个指向下一个分配块的4字节指针,一个指向前一个的4字节指针,一个用于对齐的标识符 - 单个字节可以直接处理这种情况,用于0-256字节对齐的常见大小,但该字节也可以代表256个可能的对齐枚举值,3个字节的pad或canary值,以及一个4字节的唯一标识符,用于标识代码在调用中的位置,尽管它可以做得更小。这可以是包含__file____line__的调试表的查找值,以及您希望通过分配保存的任何其他信息。

这将是较重的品种之一,因为它有很多信息需要在分配和释放值时更新。