堆内存:8字节结构的16字节间隙

时间:2014-07-02 15:49:06

标签: c memory memory-management struct heap

我正在使用以下代码创建新节点并将其插入到链接列表中,随后将其释放。

// the node
struct node
{
    int data;
    struct node *next;
};


// returns a pointer to a new node with data
struct node *new_node(int data)
{
    struct node *node;
    node = malloc(sizeof(struct node));
    node->data = data;
    node->next = NULL;
    return node;
}

// insert node at front of list
void push(struct node **head, int data)
{
    struct node *node = new_node(data);
    node->next = *head;
    *head = node;
}

// free the list, deallocate each node's memory
void delete_list(struct node** head)
{
    if(*head == NULL)
        return;

    struct node *next = NULL;
    next = (*head)->next;
    while(next != NULL)
    {
        next = (*head)->next;
                // print address of the memory released
        printf("Freeing %d\n", (int)*head);
        free(*head);
        *head = next;
    }
}

现在,结构在我的机器中是8个字节(4个字节int和4个字节指针)。现在,我对以下内容有点不确定,所以请帮助我:

  1. 当我按顺序调用push()时,内存是否连续分配?总是这样吗?我想它不可能,因为堆中的内存可能会碎片化。

  2. 假设分配的内存是连续的,那么它间隔8个字节,因为struct的大小是8个字节。在我的机器上,当我打印释放的存储器的地址时,每次执行时打印的存储器地址相隔16个字节。为什么呢?
    Freeing 148025480 Freeing 148025464 Freeing 148025448 Freeing 148025432 Freeing 148025416 Freeing 148025400 Freeing 148025384 Freeing 148025368 Freeing 148025352 <empty list>

  3. 现在如果没有为我们的整数数组连续分配内存(堆非常碎片,并且内存需求非常大),我们使用指针算法通过递增地址来处理数组的每个元素每次4个(或者int的大小),我们不应该遇到一些我们程序没有保留的内存,抛弃程序吗?或者运行时环境是否足够智能,因为编译器不能,因为它不知道如何分配内存。操作系统会处理这个问题吗?

4 个答案:

答案 0 :(得分:3)

每次拨打new_node时,都会调用malloc()

你不能(或不应该)预测malloc()会在哪里找到记忆。它取决于操作系统和运行时。

在特定操作系统上运行,在某些情况下,您可能会发现连续调用malloc()的分配是连续的。但是,这种行为可能会在加载,内核更新,libc实现的更改或各种其他条件下发生变化。

您可以假设通过对malloc()的单个调用分配的内存块是连续的(至少,就您的程序看到的指针而言)。你的程序不应该假设任何关于邻接的东西。


如果这真的困扰你,你可以在你自己的代码中负责更多的内存管理 - 而不是为每个节点调用malloc(),在开始时调用它并获得更大的内存块。对new_node的后续调用可以使用此块的一部分。如果该块中的空间不足,您可以malloc()另一个块(可能不会与第一个块连续)或realloc()来扩展(并可能移动)它。

您可能会发现所有这些都会使您的代码变得更加复杂 - 并且由您来决定是否有好处。 Hotspot Java VM的作者基本上是这样做的 - 他们malloc()在执行开始时是一大块内存,而不是在Java程序需要内存时调用malloc()free(),它使用自己的例程来分配该块的部分内容。

答案 1 :(得分:3)

关于#2,调用malloc的结果不完全连续的一个原因可能是元数据:当您要求x字节时,malloc实现可能会分配一些额外的内部簿记过程的内存(标记块的大小,指向其他空闲块的指针等)。因此,对8个字节的请求实际上可能导致在内部分配16个字节,因此连续分配之间的间隔为16个字节。

答案 2 :(得分:1)

如果使用malloc分配内存,则返回的内存将始终是连续的。

如果您拨打malloc两次,则无法保证两个分配将彼此相邻,即使两个malloc呼叫紧挨着彼此也是如此。

答案 3 :(得分:0)

使用 malloc() 分配内存时,您会看到内存分配中存在 1 字大小的间隙,即会分配 16 字节的额外空间。这是正常的,因为这是因为我们可能想要使用 free() 方法来释放内存。额外的空间被 free() 方法用作执行释放操作时的暂存空间。

Let say we have the following 2D array:
1 2 3
4 5 6
7 8 9

数组的起始地址是448(也是'1'的内存地址) 那么'1'、'4'、'7'的内存地址分别为448、480、512,计算如下:

448 + (3 x 4) + 4 + 16 = 480

Here, we have:
448 - Address of the previous block
3   - Number of columns or number of items in the array
4   - Size of int (I'm assuming the array as integer array)
4   - Extra four bytes because size of int is 4 bytes. So the last int address + 4
16  - As left by the malloc for free() function

我希望它澄清一点。