C语言malloc与free实现原理

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

当 free()将内存块置于空闲列表之上时,是如何知晓内存块大小的?这是通过一个小技巧来实现的。当 malloc()分配内存块时,会额外分配几个字节来存放记录这块内存大小的整数值

malloc()返回的内存块

image-20231018182918810

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

空闲列表中的内存块

image-20231018182947327

随着对内存不断地释放和重新分配,空闲列表中的空闲内存会和已分配的在用内存混杂在一起

包含有已分配内存和空闲内存列表的堆

image-20231018183023255

应该认识到,C 语言允许程序创建指向堆中任意位置的指针,并修改其指向的数据,包括由 free()和 malloc()函数维护的内存块长度、指向前一空闲块和后一空闲块的指针。例如,假设经由一个错误指针,程序无意间增加了冠于一块已分配内存的长度值,并随即释放这块内存,free() 因之会在空闲列表中记录下这块长度失真的内存。随后,malloc()也许会重新分配这块内存,从而导致如下场景:程序的两个指针分别指向两块它认为互不相干的已分配内存,但实际上这两块内存却相互重叠。至于其他的出错情况则数不胜数。
要避免这类错误,应该遵守以下规则。

  • 分配一块内存后,应当小心谨慎,不要改变这块内存范围外的任何内容。
  • 释放同一块已分配内存超过一次是错误的。
  • 若非经由 malloc 函数包中函数所返回的指针,绝不能在调用 free()函数时使用。
  • 在编写需要长时间运行的程序时,出于各种目的,如果需要反复分配内存,那么应当确保释放所有已使用完毕的内存。如若不然,堆将稳步增长,直至抵达可用虚拟内存的上限,在此之后分配内存的任何尝试都将以失败告终。这种情况被称之为“内存泄漏”。
  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@新法

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值