堆内存:16个字节差距8字节结构 [英] Heap memory: Gap of 16 bytes for 8 byte struct

查看:171
本文介绍了堆内存:16个字节差距8字节结构的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我用下面的code创建并插入一个新的节点到一个链表,随后解放出来。

  //节点
结构节点
{
    int数据;
    结构节点*接下来的;
};
//返回一个指向数据的新节点
结构节点* new_node(int数据)
{
    结构节点*节点;
    节点=的malloc(sizeof的(结构节点));
    与于节点GT;数据=数据;
    于节点>接着= NULL;
    返回节点;
}//在列表的前面插入节点
空推(结构节点**头,int数据)
{
    结构节点*节点= new_node(数据);
    于节点>接下来= *头;
    *头=节点;
}//释放列表中,解除分配每个节点的存储器
无效delete_list(结构节点**头)
{
    如果(*头== NULL)
        返回;    结构节点*下一= NULL;
    接下来=(*头) - >接下来,
    而(下!= NULL)
    {
        接下来=(*头) - >接下来,
                //内存打印地址公布
        的printf(舷%d个\\ N(INT)*头);
        免费(*头);
        *头=下一个;
    }
}

现在,该结构是在我的机器(4字节 INT 和4个字节的指针)8个字节。现在,我有点不确定以下,所以请帮我出:


  1. 在我称之为推()依次是内存连续分配的?是不是总是这样?我想这是不可能的,在堆内存可以被分割。


  2. 说分配的内存是连续的,这样才有间隔8个字节,因为结构的大小为8字节。在我的机器,当我被印释放的内存地址,打印的内存地址是16个字节分开,在每次执行。为什么呢?结果
    舷148025480
    释放148025464
    释放148025448
    释放148025432
    释放148025416
    释放148025400
    释放148025384
    释放148025368
    释放148025352
    <空列表>


  3. 现在,如果内存是不是我们的整型数组连续分配(堆是非常分散的,和内存的要求是相当大),我们使用指针运算通过增加地址来处理数组的每个元素4,每次(或任何 INT 的大小),难道我们不应该碰到不被我们的程序保留一些内存,摆脱了计划?或者是运行时环境聪明地照顾这一点,因为编译器不能,因为它不知道内存将如何分配。是否OS照顾这?



解决方案

每个调用时间 new_node ,它调用的malloc()

您不能(或不应该)predict其中的malloc()会找到你的记忆。它是操作系统和运行时依赖。

运行在特定的操作系统上,在某些情况下,你可能会注意到,从分配的连续通话的malloc()是连续的。但是,这种行为可能会根据负载变化,或用内核更新,在libc中执行的改变,或在各种其他条件。

您可以假设的内存由一个单一的通话分配给块的malloc()是连续(至少在程序中看到指针而言)。你的程序不应该承担任何关于连续性。


如果这真的困扰你,你可以负责更多的内存管理的在自己的code - 而不是调用的malloc()为每个节点,称它为在开始,并获得较大的内存块。到new_node后续调用可以使用此块的一部分。如果您在大块运行的空间,您可以的malloc()另一块(这可能不会是连续的,与第一)或 realloc的()延长(可能移动)吧。

您可能会发现,这一切都使得您的code更复杂 - 它取决于你是否有利益反驳说。热点Java虚拟机的作者基本上做到这一点 - 他们的malloc()的内存在执行开始的大块,然后,而不是调用的malloc ()免费()当Java程序需要​​的内存,它使用自己的程序来分配块的部分。

I'm using the following code to create and insert a new node into a linked list, subsequently freeing them.

// 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;
    }
}

Now, the struct is 8 bytes in my machine (4 byte int and 4 byte pointer). Now, I'm a bit unsure about the following, so please help me out:

  1. When I call push() in sequence, is the memory allocated contiguously? Is that always the case? I guess it cannot be, for the memory in heap can be fragmented.

  2. Say the memory allocated was contiguous, then would it be spaced 8 bytes apart, since the struct's size is 8 bytes. On my machine, when I printed the address of the memory being freed, the memory addresses printed are 16 bytes apart, on every execution. Why?
    Freeing 148025480 Freeing 148025464 Freeing 148025448 Freeing 148025432 Freeing 148025416 Freeing 148025400 Freeing 148025384 Freeing 148025368 Freeing 148025352 <empty list>

  3. Now if the memory was NOT allocated contiguously for our integer array (the heap was very much fragmented, and memory requirement was quite large), and we used pointer arithmetic to process each element of the array by incrementing the address by 4 each time(or whatever the size of int is), shouldn't we run into some memory not reserved by our program, throwing off the program? Or is the runtime environment smart enough to take care of this, as the compiler cannot, for it doesn't know how the memory will be allocated. Does the OS take care of this?

解决方案

Each time you call new_node, it calls malloc().

You cannot (or should not) predict where malloc() will find you memory. It is OS and runtime dependent.

Running on a particular OS, under certain circumstances, you might observe that allocations from consecutive calls to malloc() are contiguous. However that behaviour may change under load, or with a kernel update, a change in the implementation of libc, or under all kinds of other conditions.

You can assume that the chunk of memory allocated by a single call to malloc() is contiguous (at least, in terms of the pointers your program sees). Your program should not assume anything else about contiguity.


If this really bothers you, you can take charge of more of the memory management in your own code -- instead of calling malloc() for each node, call it at the start and get a larger chunk of memory. Subsequent calls to new_node can use part of this chunk. If you run out of space in that chunk, you can either malloc() another chunk (which probably won't be contiguous with the first) or realloc() to extend (and probably move) it.

You'll probably find that all this makes your code more complicated -- and it's up to you whether there are benefits to counter that. The authors of the Hotspot Java VM essentially do this - they malloc() a big block of memory at the start of execution, then rather than call malloc() and free() when the Java program wants memory, it uses its own routines to allocate parts of that block.

这篇关于堆内存:16个字节差距8字节结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆