c - 堆内存 : Gap of 16 bytes for 8 byte struct

标签 c memory struct memory-management heap-memory

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

// 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 的大小),难道我们不应该遇到一些没有被我们的程序保留的内存,从而退出程序吗?或者运行时环境是否足够智能来处理这个问题,因为编译器不能,因为它不知道如何分配内存。操作系统会处理这个吗?

最佳答案

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

您不能(或不应该)预测 malloc() 会在哪里找到您的内存。它依赖于操作系统和运行时。

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

您可以假设通过一次调用 malloc() 分配的内存块是连续的(至少,就您的程序所见的指针而言)。您的程序不应假设任何其他有关连续性的内容。


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

您可能会发现,所有这些都会让您的代码变得更加复杂——至于是否有好处可以抵消这种情况,则取决于您。 Hotspot Java VM 的作者基本上是这样做的——他们在执行开始时 malloc() 一大块内存,然后调用 malloc()free() 当 Java 程序需要内存时,它会使用自己的例程来分配该 block 的各个部分。

关于c - 堆内存 : Gap of 16 bytes for 8 byte struct,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24535618/

相关文章:

c# - 测量代码使用的内存

c - fork() 的意外输出

c# - Shared.CellItem' 没有实现接口(interface)成员 'System.IDisposable.Dispose()

c++ - 为什么没有在 top 和 pmap 中释放内存?

c - 如何在 C 中的结构数组中查找元素?

C++,从 'int' 到位域的隐式截断

c - 从二维数组中找到最大值,并将最大值之前的所有值相加,然后将最大值之后的所有值相乘

java - 异常处理和内存

c - 使用指针将结构体添加到数组

c - 如何在一个 C 源文件中正确使用 2 个结构定义