内存分配的间隔

Interval of memory allocation

struct Thing
{
    int member1;
    int member2;
};

struct Thing* heap()
{
    struct Thing* heap_thing = (struct Thing*)malloc(sizeof(struct Thing));

    heap_thing->member1 = 1;
    heap_thing->member2 = 2;

    printf("%p, %p, %p\n", heap_thing, &(heap_thing->member1), &(heap_thing->member2));

    return heap_thing;
}

int main(int argc, char* argv[])
{
    struct Thing* ptr = 0;
    for (int i = 0; i < 5; ++i)
    {
       ptr = heap();
       free(ptr);
    }        
    return 0;
}

我希望打印的内存地址类似于: (因为struct Thing是8个字节)

0x000008, 0x000008, 0x00000c

0x000010, 0x000010, 0x000014

0x000018, 0x000018, 0x00001c ......

但是我屏幕上显示的是:

0x000008, 0x000008, 0x00000c

0x000018, 0x000018, 0x00001c

0x000028, 0x000028, 0x00002c ......

为什么 struct Thing 成员的内存地址没有按我的预期分配? ptr之间的内存地址有16字节间隔但不是8字节?

大多数内存分配器都不是无开销的——在每个分配的块之后 and/or 之前的分配器内部使用了一些额外的内存。

在您系统的内存分配器中,这种开销似乎是每个分配块八个字节。这对于 32 位系统来说非常典型;它可能存储分配块的大小(4 字节)和指向前一个块的指针(4 字节),或类似的东西。

另一个要记住的因素是许多分配器都有最小分配量——也就是说,每个分配块的 "real" 大小都向上舍入到最接近标准大小的倍数。这是因为某些 CPU 特性(尤其是向量运算)通常需要内存与特定边界对齐,而且非常小的块难以跟踪。但是,在您的系统上,量程可能是八个字节,因此这在您的示例中没有发挥作用。 (您可以通过将结构中的一个成员从 int 更改为 char 来证明这种效果。)