【问题标题】:extra padding between structs in CC中结构之间的额外填充
【发布时间】:2020-04-30 00:16:22
【问题描述】:

我在 C 中有结构:

typedef struct Node {
    int data; // 4 bytes int + 4 bytes for alignment
    struct Node* prev; // 8 bytes pointer
    struct Node* next; // 8 bytes pointer
} Node;

这个结构的大小是 24 字节 (8 + 8 + 8)。当我使用 sizeof(Node) 时,编译器也会显示 24 个字节。

但是,当我在堆上(一个接一个)创建两个或多个结构并查看它们的内存位置时,每个 Node 结构之间存在 8 个字节间隙。 例如:

11121344 (the 1st Node address)
11121376 (the 2nd Node address) // 376-344 = 32-24 = 8 extra bytes
11121408 (the 3rd Node address) // 408-376 = 32-24 = 8 extra bytes

你能解释一下为什么编译器通过在 Node 之间添加 8 个字节来分隔 Node 结构吗?

【问题讨论】:

  • 我猜原因是结构字对齐。它有利于内存访问。
  • 如果你在堆上创建它们,那么所有的赌注都与它们分配的内存地址有关。
  • 秘诀在于你是如何“创建两个或更多结构”的。这是一个数组吗?如果不是,为什么期望内存地址之间有任何东西
  • malloc(sizeof(Node) * 3) 是一个由 3 个结构组成的数组,其中您期望某些相对地址。 malloc(sizeof(Node)); malloc(sizeof(Node)); malloc(sizeof(Node)); 是 3 个完全不相关的对象,每个对象都可以在任何地方。
  • Malloc 也在使用一些内存来进行内部簿记(有时还使用金丝雀来检测损坏)。有几种可能的策略,其中一些可能会以这种方式显示出来。

标签: c gcc memory


【解决方案1】:

您的观察可能有 2 个原因:

  1. C 标准要求 malloc 始终返回具有最大对齐的内存块,以防止出现对齐问题,无论您分配什么。
  2. malloc 通过使用某种数据结构在内部管理内存块。根据实现,它会为每个内存块添加额外的信息以供内部使用。例如,malloc 可以管理链表中的内存块,然后它会要求每个块保存一个指向下一个块的附加指针。

最大对齐取决于架构和编译器/malloc - 使用的实现。

对于您的情况并假设 glibc,直接从 glibc/malloc.c 的文档中取出:

 Alignment:                              2 * sizeof(size_t) (default)
       (i.e., 8 byte alignment with 4byte size_t). This suffices for
       nearly all current machines and C compilers. However, you can
       define MALLOC_ALIGNMENT to be wider than this if necessary.
  Minimum overhead per allocated chunk:   4 or 8 bytes
       Each malloced chunk has a hidden word of overhead holding size
       and status information.
  Minimum allocated size: 4-byte ptrs:  16 bytes    (including 4 overhead)
              8-byte ptrs:  24/32 bytes (including, 4/8 overhead)

因此,在您的情况下,malloc 将与 2 * sizeof(size_t) = 对齐 16 个字节。

还要注意提到的“隐藏开销”。此开销是由于存储用于内存管理的其他内部信息...

【讨论】:

    【解决方案2】:

    你能解释一下为什么编译器通过在 Node 之间添加 8 个字节来分隔 Node 结构吗?

    这是一个巧合。对于任何malloc() 调用序列如何布局内存没有规则。

    地址可以按固定间隔升序,按不同间隔降序,(看似)随机,...,...

    如果您想要固定的相对地址,请使用数组

    struct Node arr[3];
    ptrdiff_t delta10 = &arr[1] - &arr[0];
    ptrdiff_t delta20 = &arr[2] - &arr[0];
    ptrdiff_t delta21 = &arr[2] - &arr[1];
    if (delta10 != delta21) /* cannot happen */;
    

    或者同时分配一组元素(可能是realloc()

    struct Node *elements = malloc(3 * sizeof *elements);
    ptrdiff_t delta10 = &elements[1] - &elements[0];
    ptrdiff_t delta20 = &elements[2] - &elements[0];
    ptrdiff_t delta21 = &elements[2] - &elements[1];
    if (delta10 != delta21) /* cannot happen */;
    free(elements);
    

    【讨论】:

    • 从随机机会的意义上说,这种行为不太可能是“巧合”。这可能是 C 标准要求 malloc 返回内存适合任何具有基本对齐要求的对象或内存管理功能设计的结果。
    猜你喜欢
    • 1970-01-01
    • 2023-04-03
    • 2012-06-25
    • 2010-09-27
    • 2015-04-25
    • 1970-01-01
    • 1970-01-01
    • 2018-03-30
    • 2014-10-12
    相关资源
    最近更新 更多