C语言编写一个简单的内存分配器:大家都以为简单,实则暗藏玄机
本文主要介绍如何用C语言编写一个简单的内存分配器。我们将实现malloc()
、calloc()
、realloc()
和free()
函数。
这是一篇面向初学者的文章,因此我不会详述每一个细节。这个内存分配器不会很快且高效,我们也不会调整已分配的内存使其与页面边界对齐,但我们会构建一个能正常工作的内存分配器,仅此而已。(如果你想查看完整的代码私聊我)在开始构建内存分配器之前,你需要熟悉程序的内存布局。一个进程在其自己的虚拟地址空间中运行,该虚拟地址空间与其他进程的虚拟地址空间是不同的。这个虚拟地址空间通常由五个部分组成:
- 文本段:包含要由处理器执行的二进制指令的部分。
- 数据段:包含已初始化且值不为零的静态数据。
- BSS段(由符号开始的块):包含已初始化为零的静态数据。程序中未初始化的静态数据会被初始化为0并存储在这里。
- 堆:包含动态分配的数据。
- 栈:包含自动变量、函数参数、基指针的副本等。
从图中可以看到,栈和堆的增长方向是相反的。有时,数据段、BSS段和堆段会被统称为“数据段”,其末尾由一个名为程序断点(program break)或brk
的指针来界定。也就是说,brk
指向堆的末尾。
现在,如果我们想在堆中分配更多内存,就需要请求系统增加brk
的值。同样,要释放内存,我们需要请求系统减小brk
的值。
假设我们运行的是Linux(或类Unix系统),我们可以使用sbrk()
系统调用来操作程序断点。
- 调用
sbrk(0)
会返回程序断点的当前地址。 - 调用
sbrk(x)
(x
为正值)会使brk
增加x
个字节,从而分配内存。 - 调用
sbrk(-x)
(x
为正值)会使brk
减少x
个字节,从而释放内存。
如果调用失败,sbrk()
会返回(void*) -1
。
说实话,sbrk()
并不是我们最好的选择。如今有更好的替代方案,比如mmap()
。sbrk()
并不是线程安全的,并且它只能按照后进先出(LIFO)的顺序增长或收缩。

扫描二维码关注微信公众号,回复密码,即可获取密码
阅读剩余
版权声明:
作者:讳疾忌医-note
链接:https://www.1217zy.vip/archives/75
文章版权归作者所有,未经允许请勿转载。
THE END