malloc() 和 free() 函数的陷阱

本文将简要介绍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型。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值