对堆的基本了解

时间:2014-12-20 12:39:17

标签: c memory-management heap-memory

我想了解更多关于堆上发生的事情。所以我看看下面的C代码。它基本上只是在堆上为两个变量分配内存:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char* argv[])
{
    char *char_ptr;
    int *int_ptr;
    int mem_size;

    if(argc < 2)
        mem_size = 50;
    else
        mem_size = atoi(argv[1]);

    printf("\t[+] allocating %d bytes of memory on the heap for char_ptr\n", mem_size);
    char_ptr = (char *) malloc(mem_size);
    if(char_ptr == NULL)
    {
        fprintf(stderr, "Error: could not allocate heap memory. \n");
        exit(-1);
    }

    strcpy(char_ptr, "This is memory located on the heap.");
    printf("char_ptr (%p) --> '%s'\n", char_ptr, char_ptr);

    printf("\t[+] allocating 12 bytes of memory on the heap for int_ptr\n");
    int_ptr = (int * ) malloc(12);
    if(int_ptr == NULL)
    {
        fprintf(stderr, "Error: could not allocate heap memory.");
        exit(-1);
    }

    *int_ptr = 31337;
    printf("int_ptr  (%p) --> %d\n", int_ptr, *int_ptr);

    printf("\t[-] freeing char_ptr's heap memory...\n");
    free(char_ptr);

    printf("\t[+] allocating another 15 bytes for char_ptr\n");
    char_ptr = (char *) malloc(15);
    if(char_ptr == NULL)
    {
        fprintf(stderr,"Error: could not allocate heap memory.\n");
        exit(-1);
    }

   strcpy(char_ptr, "new memory");
   printf("char_ptr (%p) --> '%s'\n", char_ptr, char_ptr);

   free(int_ptr);
   free(char_ptr);
}

此代码的输出如下所示:

    [+] allocating 50 bytes of memory on the heap for char_ptr
char_ptr (0x8827008) --> 'This is memory located on the heap.'
    [+] allocating 12 bytes of memory on the heap for int_ptr
int_ptr  (0x8827040) --> 31337
    [-] freeing char_ptr's heap memory...
    [+] allocating another 15 bytes for char_ptr
char_ptr (0x8827050) --> 'new memory'

所以我猜猜char_ptr指向已分配内存的开头( 0x8827008 ),对吗?

由于分配了50个字节,因此该存储器的末尾应指向地址0x882702A。下一个内存分配从地址 0x8827040 开始。我的问题是:为什么int_ptr不指向 0x882702B (第一次内存分配后的下一个地址)?或者换句话说: 0x772702A 0x8827040 之间内存发生了什么?

4 个答案:

答案 0 :(得分:3)

具体取决于您的C库(依赖于您的操作系统)。导致这种现象的原因有两个:

  1. 从malloc获得的每个内存块都以标题为前缀(通常为16个字节)。但是,malloc只返回指向标题之后的指针。
  2. 每个内存块必须与最大对齐单元的倍数对齐。通常(取决于微处理器),最大对齐为8个字节。用于实现对齐的字节称为填充。
  3. 结果,以... 2A结尾的块被填充到... 30,然后添加16个字节的malloc头,并且你的下一个块从......开始。

答案 1 :(得分:2)

malloc()不必在下一个内存地址分配。以下是一些原因:

  • malloc()仅保证返回一些已分配的内存。它的工作原理是malloc() - 从界面定义的角度来看,它是一个黑盒子。弄清楚里面发生的事情可能很有趣,但不是标准的一部分。

  • malloc()会将分配与方便的边界对齐(通常是64位平台上的64位边界)。

  • 之前的其他库调用可能会有free()&#39; d块,因此您可以在一个洞内进行分配 - 即在之前的free() d块内存中

  • 描述堆的内部数据结构紧接在分配数据结构之前。在一个简单的实现中,它们将是一个链表。

  • malloc()从多个地方获取记忆;是的,它使用堆(和brk / sbrk),但对于更大的分配,它将mmap()MAP_ANON一起使用。

所有这些因素都可能导致分配不在下一个内存地址中。

答案 2 :(得分:1)

可能是因为堆的控制信息是内联存储的。

换句话说,每个块可能有一个隐藏的&#39;它之前的部分包含控件信息,如块大小,链接到下一个块,标记以检测损坏等等。

它还可能为您提供比请求更多的内存,例如确保它是十六个字节的倍数(尽管您仍然只允许使用您要求的内容)。

然而,底线是你不能依赖任何一个。对于不同的实现,不同的版本或代码运行的那一天,它可能会发生变化: - )

您可以确定它在标准中的含义 - 它将为您提供NULL或可用地址,可以

答案 3 :(得分:1)

谢谢大家的回答!他们帮了很多忙!我对堆的概念有一个基本的误解。

总结已经说过的话:

  1. 除了实际值之外,每个内存块还有“隐藏”信息
  2. 堆不需要将各个内存块“串在一起”
  3. 不幸的是,我不能给你们任何人投票,因为我没有15点声望。我希望你原谅我; - )