首页 文章

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

提问于
浏览
1

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

// 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字节指针) . 现在,我对以下内容有点不确定,所以请帮助我:

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

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

  • 现在,如果没有为我们的整数数组连续分配内存(堆非常碎片,并且内存需求非常大),我们使用指针算法通过每次递增地址4来处理数组的每个元素(或者无论 int 的大小是什么,都不应该知道如何分配内存 . 操作系统会处理这个问题吗?

3 回答

  • 3

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

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

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

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


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

    你是否有好处才能解决这个问题 . Hotspot Java VM的作者基本上是这样做的 - 他们在执行开始时是一个很大的内存块,而不是在Java程序需要内存时调用 malloc()free() ,它使用自己的例程来分配该块的部分内容 .

  • 1

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

  • 3

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

    如果你两次调用 malloc ,则无法保证两个分配将彼此相邻放置,即使两个 malloc 调用彼此相邻也是如此 .

相关问题