浅谈malloc()和free()工作原理


编程之路刚刚开始,错误难免,希望大家能够指出。 

malloc()和free()是我经常需要用到的函数,一般情况下,C程序使用malloc()在堆上分配内存,free()释放内存,两者的参数和返回值就不在这叙述了,本文主要是简单的记录下malloc()和free()的工作原理。

malloc()返回内存块所采用的字节对齐方式,总是适宜于高效访问任何类型的C语言数据结构。在大多数硬件架构上,这实际意味着malloc是基于8字节或16字节边界来分配内存的。若无法分配内存,或许是因为已经抵达program break所能达到的地址上限,但一般分配内存失败的可能性很小。

一般情况下,free()并不降低program break的位置,而是将这块内存添加到空闲内存列表中,供后续的malloc()循环使用,原因有以下几点:

  1.被释放的内存块通常会位于堆的中间,而非堆的顶部,因为降低program break是不可能的;

  2.它最大限度地减少了程序必须执行的sbrk()调用次数,其实就是降低系统调用的开销;

  3.多数情况下,降低program break的位置不会对那些分配大量内存的程序有多少帮助,因为它们通常倾向于持有已分配内存或是反复释放和重新分配内存,而非释放所有内存后再持续运行一段时间。

malloc()工作原理:

  它首先会扫描之前由free()所释放的空闲内存块列表,以求找到尺寸大于或等于要求的一块空闲内存,如果这一内存块的尺寸正好与要求想当,就把该内存块地址直接返回给调用者,如果是一块较大的内存,那么将对其进行分割,在将一块大小相当的内存返回给调用者的同时,把较小的那块空闲内存保留在空闲列表中。如果空闲内存列表中没有足够大的空闲内存块,那么malloc()会调用sbrk()以分配更多的内存。为减少对sbrk()的调用次数,malloc()并未只是严格按所需字节数来分配内存,而是以更大幅度(以虚拟内存页大小的数倍)来增加program break,并将超出部分置于空闲内存列表。

  malloc()分配内存块的时候,会额外分配几个字节来记录内存块的大小,该数值存放在内存块的起始处,malloc()实际返回给调用者的地址其实是该数值之后的内存块长度。

free()工作原理:

  free()将内存块置于空闲链表中是根据该内存块所记录的内存块大小来实现的。

  当将内存块置于空闲内存列表(双向链表)时,free()会使用内存块本身的空间来存放链表指针,将自身添加到列表中。

所以,实际上的堆是空闲内存和已分配在用内存的混合,如下图:

了解了两者的工作原理,我们在使用的时候一定要切记free()只能释放malloc()返回的指针,并且程序中有malloc(),就一定要有free()。

简单记录malloc调试工具mtrace:

  代码:

 1 #include 
 2 #include 
 3 #include 
 4 
 5 int main()
 6 {
 7     setenv("MALLOC_TRACE","output.txt",1);
 8     mtrace();
 9 
10     int *p = (int *)malloc(2 * sizeof(int));
11 
12     return 0;
13 }

  执行命令:

  mtrace和addr2line配合起来还是不错滴。

  addr2line 可看http://www.cnblogs.com/jiangyibo/p/8653720.html

  mtrace调试动态库推荐http://blog.sina.com.cn/s/blog_590be5290102vtdb.html

相关