当前位置:   article > 正文

malloc() 和 free() 函数的陷阱_qt的释放函数free

qt的释放函数free

本文将简要介绍malloc和free两个函数,并详细说明这两个函数的实现。

函数原型

malloc用于动态分配内存。首先看malloc原型:

  1. #include <stdlib.h>
  2. void *malloc(size_t size );
  3. \\Returns pointer to allocated memory on success, or NULL on error
malloc返回void*类型的指针,所以可以赋给任何类型的C指针。要注意参数是指字节数。如果不能成功分配内存,则返回NULL,并设置errno值。

free函数用于释放有malloc函数族分配的内存。下面是free函数原型:

  1. #include <stdlib.h>
  2. 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型。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Li_阴宅/article/detail/969188
推荐阅读
相关标签
  

闽ICP备14008679号