我使用下面的代码来创建一个新节点并将其插入到一个链接列表中,然后释放它们。
// 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()时,内存是否被连续分配?总是这样吗?我想是不可能的,因为堆中的内存可以是分段的。struct的大小是8字节。在我的机器上,当我打印释放内存的地址时,每次执行时,打印的内存地址都是16字节。为什么?
Freeing 148025480 Freeing 148025464 Freeing 148025448 Freeing 148025432 Freeing 148025416 Freeing 148025400 Freeing 148025384 Freeing 148025368 Freeing 148025352 <empty list>int的大小),难道我们不应该遇到程序没有保留的内存,抛出程序吗?或者运行时环境足够聪明来处理这个问题,因为编译器不能这样做,因为它不知道如何分配内存。操作系统会处理这个问题吗?发布于 2014-07-02 15:57:15
每次您调用new_node时,它都会调用malloc()。
您不能(或者不应该)预测malloc()将在哪里找到您的内存。它依赖于操作系统和运行时。
在特定的操作系统上运行,在某些情况下,您可能会发现,从连续调用到malloc()的分配是连续的。但是,这种行为在加载或内核更新时、在libc实现中的更改或在各种其他条件下都可能发生变化。
您可以假设对malloc()的单个调用分配的内存块是连续的(至少在程序看到的指针方面是这样的)。您的程序不应该假设其他任何关于毗连的东西。
如果这真的困扰您,您可以在您自己的代码中负责更多的内存管理--而不是为每个节点调用malloc(),而是在开始时调用它,并获得更大的内存块。随后对new_node的调用可以使用该块的一部分。如果该块中的空间不足,您可以malloc()另一个块(可能不会与第一个块相邻)或realloc()来扩展(并且可能会移动)它。
您可能会发现,所有这些都会使您的代码变得更加复杂--这取决于您是否有解决这些问题的好处。Hotspot Java的作者基本上就是这样做的--他们在执行开始时使用了一个大的内存块,然后当Java程序需要内存时,它不会调用malloc()和free(),而是使用自己的例程来分配块的一部分。
发布于 2014-07-02 16:19:08
关于#2,调用malloc的结果不完全连续的一个原因可能是元数据:当您请求x字节时,malloc实现可能为内部簿记过程分配一些额外的内存(标记块的大小、指向其他空闲块的指针等)。因此,对8个字节的请求实际上可能导致内部分配16个字节,因此连续分配之间的16字节间隔。
发布于 2014-07-02 15:52:46
如果使用malloc分配内存,则返回的内存将始终是连续的。
如果您两次调用malloc,就不能保证这两个分配将放在一起,即使两个malloc调用就在一起。
https://stackoverflow.com/questions/24535618
复制相似问题