C语言malloc与free实现原理

简介: malloc()的实现很简单。它首先会扫描之前由 free()所释放的空闲内存块列表,以求找到尺寸大于或等于要求的一块空闲内存。(取决于具体实现,采用的扫描策略会有所不同。例如,first-fit 或 best-fito。)如果这一内存块的尺寸正好与要求相当,就把它直接返回给调用者。如果是一块较大的内存,那么将对其进行分割,在将一块大小相当的内存返回给调用者的同时,把较小的那块空闲内存块保留在空闲列表中。 如果在空闲内存列表中根本找不到足够大的空闲内存块,那么 malloc()会调用 sbrk()以分配更多

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()函数时使用。
  • 在编写需要长时间运行的程序时,出于各种目的,如果需要反复分配内存,那么应当确保释放所有已使用完毕的内存。如若不然,堆将稳步增长,直至抵达可用虚拟内存的上限,在此之后分配内存的任何尝试都将以失败告终。这种情况被称之为“内存泄漏”。
目录
相关文章
|
14天前
|
程序员 C语言 开发者
pymalloc 和系统的 malloc 有什么区别
pymalloc 和系统的 malloc 有什么区别
|
10天前
|
程序员 C语言 开发者
pymalloc 和系统的 malloc 有什么区别?
pymalloc 和系统的 malloc 有什么区别?
|
5月前
|
存储 C语言
malloc
【6月更文挑战第16天】
67 8
|
1月前
|
程序员 编译器 C语言
C中的 malloc 和C++中的 new 有什么区别
在C语言中,`malloc`函数用于在运行时分配内存,返回指向所分配内存的指针,需显式包含头文件 `<stdlib.h>`。而在C++中,`new`不仅分配内存,还对其进行构造初始化,且直接使用类型声明即可,无需额外包含头文件。`new`还支持数组初始化,能更好地融入C++的面向对象特性,而`malloc`仅作为内存分配工具。使用完毕后,`free`和`delete`分别用于释放`malloc`和`new`分配的内存。
51 21
|
5月前
|
存储 C语言
C语言学习记录——动态内存函数介绍(malloc、free、calloc、realloc)
C语言学习记录——动态内存函数介绍(malloc、free、calloc、realloc)
326 1
|
1月前
|
自然语言处理 编译器 Linux
C语言中抽象的编译和链接原理
C语言中抽象的编译和链接原理
20 1
|
5月前
|
C语言
【C语言】:动态内存管理函数malloc,calloc,realloc和free的介绍的介绍
【C语言】:动态内存管理函数malloc,calloc,realloc和free的介绍的介绍
64 0
|
3月前
|
存储 NoSQL Java
线程池的原理与C语言实现
【8月更文挑战第22天】线程池是一种多线程处理框架,通过复用预创建的线程来高效地处理大量短暂或临时任务,提升程序性能。它主要包括三部分:线程管理器、工作队列和线程。线程管理器负责创建与管理线程;工作队列存储待处理任务;线程则执行任务。当提交新任务时,线程管理器将其加入队列,并由空闲线程处理。使用线程池能减少线程创建与销毁的开销,提高响应速度,并能有效控制并发线程数量,避免资源竞争。这里还提供了一个简单的 C 语言实现示例。
|
5月前
|
存储 算法 C语言
二分查找算法的概念、原理、效率以及使用C语言循环和数组的简单实现
二分查找算法的概念、原理、效率以及使用C语言循环和数组的简单实现
|
5月前
|
算法 搜索推荐 C语言
深入了解C语言的qsort函数:原理及相关知识
深入了解C语言的qsort函数:原理及相关知识
76 1