【问题标题】:Why are address are not consecutive when allocating single bytes?为什么分配单个字节时地址不连续?
【发布时间】:2013-01-14 23:39:07
【问题描述】:

我动态分配内存如下:

char* heap_start1 = (char*) malloc(1);
char* heap_start2 = (char*) malloc(1);

当我按如下方式执行 printf 时,地址不是连续的。

printf("%p, %p \n",heap_start1,heap_start2);

结果:

   0x8246008, 0x8246018

如您所见,有 15 字节的额外内存需要进行碎片整理。这绝对不是因为单词对齐。这种奇特的对齐方式背后有什么想法吗?

提前致谢!

如果这很重要,我在 linux 中使用 gcc。

【问题讨论】:

  • 另外:Malloc 需要一些空间来自己记账。这通常是“N 字节”(对于一些小的 N)返回的指针之前。
  • 规范要求 malloc() 返回一个指针,该指针适合任何具有基本对齐要求的对象对齐。这几乎肯定大于 1。
  • 另一个注意事项 - 您不需要在 C 程序中强制转换 malloc() 的返回值。
  • “令人惊讶的是地址不是连续的”——相反,如果它们是连续的,那将是非常令人惊讶的。 “这绝对不是因为单词对齐” - 取决于您所说的“单词”是什么意思。请阅读 malloc 文档。

标签: c unix alignment malloc


【解决方案1】:

glibc 的malloc,对于小于 16 字节的小内存分配,只是将内存分配为 16 字节。这是为了防止在释放此内存时出现外部碎片,其中可用内存块太小而无法在一般情况下用于完成新的malloc 操作。

malloc 分配的块也必须足够大,以便在存储空闲块的数据结构中存储跟踪它所需的数据。

这种行为虽然会增加内部碎片,但会减少整个系统的整体碎片。

来源: http://repo.or.cz/w/glibc.git/blob/HEAD:/malloc/malloc.c (特别阅读第 108 行)

/*
...
Minimum allocated size: 4-byte ptrs:  16 bytes    (including 4 overhead)
...
*/

此外,glibc 中 malloc 调用返回的所有地址都与:2 * sizeof(size_t) 字节对齐。对于 32 位系统(例如您的系统)是 64 位,对于 64 位系统是 128 位。

【讨论】:

    【解决方案2】:

    至少三个可能的原因:

    • malloc 需要为所有原始类型生成适当对齐的内存。 SSE 指令的数据需要 128 位对齐。 (目前我还没有想到您的平台支持的其他 128 位原始类型。)

    • malloc 的典型实现涉及“过度分配”,以便为快速的free 存储簿记信息。不确定 Linux 上的 GCC 是否这样做。

    • 它可能正在分配guard bytes,以便检测缓冲区溢出等。

    【讨论】:

    • 但是为什么你仍然可以对不是 128 位对齐的数组成员执行操作呢?我认为这不仅仅是内存对齐。
    • @AndrewDunn:你说的是 SSE 操作?我认为 SSE4 增加了对未对齐访问的支持(尽管这不是我的专业领域!)。
    • 如原始问题所示,0x8246008 无论如何都没有与 128 位对齐。
    • 我认为 long long 类型只是 64 位对齐。 OP 使用的是 32 位机器,基于那些 %p 打印的长度。
    • 所有 SSE 代都允许对大多数指令进行非对齐访问,但会降低速度。
    【解决方案3】:

    malloc 保证返回的内存对于任何基本类型都正确对齐。此外,内存块可以填充一些保护字节以检查内存损坏,这取决于设置。

    【讨论】:

      【解决方案4】:

      如果你想分配连续的地址,你应该在同一个 malloc 上分配它们

      char *heap_start1, *heap_start2;
      heap_start1 = (char*) malloc(2 * sizeof(char));
      heap_start2 = heap_start1 + 1;
      

      【讨论】:

      • 这只是一种更好的编码习惯,你不能假设 char 的大小是 1... 在 heap_start2 赋值中你可以使用 +1 因为它是一个指针算法所以它会继续自动添加 char 的大小。
      • sizeof(char) 始终为 1。始终。它在语言的定义中。如果您想要更好的编码练习,我可以也许支持malloc(2 * sizeof *heap_start),以防您以后更改类型。
      • 什么?不,这将为两个指针分配空间。你想要两个chars,对吧?我确实错过了1 - 抱歉:malloc(2 * sizeof *heap_start1)
      • 永远不要假设 C 中任何数据类型的大小,尤其是在您为重用而编写代码时。你永远无法判断你的代码可以编译成什么样的架构。
      • @Andrew,sizeof(char) 不会改变。我完全赞成小心并编写可重用的代码,但添加不必要的混乱并不算数。
      猜你喜欢
      • 2013-10-08
      • 1970-01-01
      • 1970-01-01
      • 2014-10-29
      • 2015-08-29
      • 2016-03-15
      • 2019-04-02
      • 2015-09-29
      • 1970-01-01
      相关资源
      最近更新 更多