赞
踩
本文将简要介绍malloc和free两个函数,并详细说明这两个函数的实现。
malloc用于动态分配内存。首先看malloc原型:
- #include <stdlib.h>
- void *malloc(size_t size );
- \\Returns pointer to allocated memory on success, or NULL on error
malloc返回void*类型的指针,所以可以赋给任何类型的C指针。要注意参数是指字节数。如果不能成功分配内存,则返回NULL,并设置errno值。
free函数用于释放有malloc函数族分配的内存。下面是free函数原型:
- #include <stdlib.h>
- void free(void * ptr);
通常free并不改变程序的内存break值,而是将释放的内存块加入到空闲内存块表中。空闲内存块表中的内存块可由malloc分配使用。
注意:不能对同一个地址(或叫做指针)进行两次free。一个好的习惯是在free后将指针赋值为NULL。对NULL指针调用free,不做任何事。
下面进入本文的重点,两个函数的实现:
malloc的实现比较简单。在调用malloc进行内存分配时,首先扫描由free释放的空闲内存块表,如果有一个块的大小大于或等于要求分配的内存大小(具体的扫描策略依赖于实现,比如first-fit或best-fit),则将此块的地址返回给程序使用。如果扫描到的内存块的大小等于要分配的内存大小,直接返回其地址。如果扫描到的内存块大小大于要求的大小,则将此内存块进行分割,返回需要的部分,并将剩余部分加入到空闲内存块表,以备将来malloc使用。如果空闲内存表上没有合适的内存块,或者干脆是个空表,则malloc将调用系统调用sbrk()来给程序分配更多内存。为了尽可能减少sbrk()系统调用,sbrk()增大的值将比malloc需要的内存块大一些。
在考虑到free时,许多初学者会有一个疑问,我们只给free传递了一个指针值,free怎么知道要释放多大的内存呢。实际上malloc的实现有一个小的技巧下图是malloc的示意图:
malloc分配额外的内存空间用来存储所分配空间的大小,这个额外的空间就在malloc返回的地址前。当我们调用free时,这块内存将作为空闲内存块存放在空闲内存块表中。空闲内存块表为了减少存储空间,采用了一个十分巧妙的方法,那就是把双向链表指针以及内存块大小存储在空闲内存块中,而不是再分配空间用来记录空闲内存块的指针。示意图如下:
看了以上实现一节,我们不难发现malloc和free真是两个危险的函数啊。首相malloc和free分配释放的是堆上的内存空间。一些系统上允许程序自由访问这些空间。对于malloc返回的指针ptr,很容易使用移动操作,ptr--将是一个危险的操作,我们很可能一不小心改变了malloc额外分配的长度字段,直接造成free时多释放或少释放内存。对于已释放的指针,再次释放或再次访问的情况也有可能发生,有些系统上可能会触发一个 SIGSEGV信号,指示内存访问错误,但也有可能系统并不提示。对于free后的内存块,我们看到,free函数在把内存块放到空闲内存块链表时,会改变内存块的内容。
另一个重要的提示,许多朋友看了实现一节,可能想自己写程序查看一下malloc额外分配的长度值,会发现一般情况下,这个长度值比我们要求分配的值大,这是从效率角度考虑的,额外分配的是一个size_t类型的长度,一般size_t定义为unsigned long型。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。