【问题标题】:If I malloc(1) twice in a row, why do the values differ by 32?如果我连续两次 malloc(1),为什么值相差 32?
【发布时间】:2014-04-06 20:40:25
【问题描述】:

在 C 中,如果我运行 malloc(1) 两次,然后打印出转换为 uintptr_t 的两个值,则这些值相差 32。例如,

void * last = malloc(1);
void * next = malloc(1);
printf("orig %lu\n", ((uintptr_t)last));
printf("next %lu\n", ((uintptr_t)next));

打印出来

orig 30572560
next 30572592

malloc(size_t size) 根据this 分配大小字节。当我malloc 一个字节,然后是另一个字节时,我希望该值增加 8。为什么它们相差 32?谢谢!

【问题讨论】:

  • 不是 ans 而是使用%p 打印指针。
  • 我想要十进制表示,而不是十六进制,这就是为什么我没有使用 %p

标签: c memory malloc


【解决方案1】:

这实际上是不同编译器/标准库之间的实现细节。通常,不能保证您随后的malloc 调用将返回相邻的内存区域。另请注意,每个内存区域都与其他元数据相关联,包括但不限于区域大小(否则无法知道运行free 时要释放多少内存)。此元数据通常放在分配的区域内,使其大于请求的区域。还有一些其他因素会影响实际分配的内存量 - malloc 实现使用的内存对齐和“漏洞”查找算法等。

【讨论】:

    【解决方案2】:

    因为内存分配器在指定的边界上工作。在你的情况下 - 它的 32 个字节(不是位,字节)。

    有一种名为pointer tagging 的好技术滥用它来节省空间。请参阅此博客文章以了解如何(基本上 - 他们将状态保存在指针的低位中,并且在读取指针的内容之前,他们将 LSB“归零”)。

    http://jkt.flaska.net/blog/Tagged_pointers__and_saving_memory_in_Trojita.html

    【讨论】:

      【解决方案3】:

      Malloc 可能不保证连续的内存地址。这取决于编译器。另请注意,内存访问在特定边界处以最佳方式完成,例如 4 个字节(或在其他架构上为 8 个字节),因此如果 malloc 确实提供了连续的内存地址,它可能会插入填充以避免逐字节寻址。

      还可以使用%p 打印您的指针,而不是整数。

      【讨论】:

      • 根据您的推理,差异将是 4,而不是 32(差异不是以 bits 衡量的)。
      • @ktodisco:指针的值保持不变,不受格式说明符的影响。
      • @brokenfoot 它们将以不同的方式打印。在示例程序中试一试。例如,使用%p 打印指针我得到0x002E9390,使用%lu 我得到3052432。格式说明符确实很重要。但是,我对 malloc 给出后续对齐的内存地址是错误的,并且会更正答案。
      • @ktodisco: %p 打印十六进制值 & lu 无符号整数。该值仍然保持不变。 0x002E9390的十进制值,我查了一下,确实是3052432
      • @brokenfoot 是的。我确实 not 说这些值会改变。我说它们会以不同的方式打印。一个以 10 为底,另一个以 16 为底。
      【解决方案4】:

      malloc() 保证返回一个指针,该指针指向至少您请求大小的块,并以适当的对齐方式存储您请求大小的任何对象或NULL
      malloc() 如何获取和分配这些块完全是在这些边界内定义的实现,您不应以任何方式依赖它。
      因为malloc() 必须为free() 存储一些簿记数据,并且必须保证更大请求的对齐,所以您在这种情况下的实现不知何故给了您32 字节的块。

      旁白:不允许将指针减去不同的内存块。 此外,您的程序通过尝试打印 uintptr_t 来引发未定义的行为:正确的格式说明符是 PRIdPTR

      琐事:让free()什么都不做是一个有效的选择,这意味着可以省略记账数据。

      【讨论】:

      • “支持”,在你的最后一句话中,不是一个好词。它可能受支持,并且在大多数情况下是受支持的,但此行为取决于实现/架构且非标准。
      【解决方案5】:

      Malloc 确保数据存储在连续内存中(可能会进行一些填充/对齐),前提是您在一次调用 malloc 时分配了一些块。像

      char *p = malloc(sizeof(char)*2);
      

      这里p[0]p[1]的地址是连续的。
      但是对于:

      char *p1 = malloc(sizeof(char));
      char *p2 = malloc(sizeof(char));  
      

      无法保证,它可能/可能不会找到连续的内存来分配p1p2指向的块。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-11
        • 1970-01-01
        相关资源
        最近更新 更多