malloc 底层实现及原理
摘要:偶尔看到面试题会问到 malloc 的底层原理,今天就来记录一下,毕竟学习要“知其所以然”,这样才会胸有成竹。
注:下面分析均是基于 linux 环境下的 malloc 实现。步骤是:先总结结论,再逐步展开
结论
1)当开辟的空间小于 128K 时,调用 brk()函数,malloc 的底层实现是系统调用函数 brk(),其主要移动指针 _enddata(此时的 _enddata 指的是 Linux 地址空间中堆段的末尾地址,不是数据段的末尾地址)
2)当开辟的空间大于 128K 时,mmap()系统调用函数来在虚拟地址空间中(堆和栈中间,称为“文件映射区域”的地方)找一块空间来开辟。
具体内容
当一个进程发生缺页中断的时候,进程会陷入核心态,执行以下操作:
1)检查要访问的虚拟地址是否合法
2)查找/分配一个物理页
3)填充物理页内容(读取磁盘,或者直接置0,或者什么都不做)
4)建立映射关系(虚拟地址到物理地址的映射关系)
5)重复执行发生缺页中断的那条指令
如果第3布,需要读取磁盘,那么这次缺页就是 majfit(major fault:大错误),否则就是 minflt(minor fault:小错误)
内存分配的原理
从操作系统角度看,进程分配内存有两种方式,分别由两个系统调用完成:brk 和 mmap (不考虑共享内存)
1)brk 是将数据段(.data)的最高地址指针 _edata 往高地址推
2)mmap 是在进程的虚拟地址空间中(堆和栈中间,称为“文件映射区域”的地方)找一块空闲的虚拟内存。
这两种方式分配的都是虚拟内存,没有分配物理内存。在第一次访问已分配的虚拟地址空间的时候,发生缺页中断,操作系统负责分配物理内存,然后建立虚拟内存和物理内存之间的映射关系。
具体分配过程
情况一:malloc 小于 128K 的内存,使用 brk 分配
将_edata往高地址推(只分配虚拟空间,不对应物理内存(因此没有初始化),第一次读/写数据时,引起内核缺页中断,内核才分配对应的物理内存,然后虚拟地址空间建立映射关系),如下图:

1,进程启动的时候,其(虚拟)内存空间的初始布局如图1所示
2,进程调用A=malloc(30K)以后,内存空间如图2:
malloc函数会调用brk系统调用,将_edata指针往高地址推30K,就完成虚拟内存分配
你可能会问:难道这样就完成内存分配了?
事实是:_edata+30K只是完成虚拟地址的分配,A这块内存现在还是没有物理页与之对应的,等到进程第一次读写A这块内存的时候,发生缺页中断,这个时候,内核才分配A这块内存对应的物理页。也就是说,如果用malloc分配了A这块内容,然后从来不访问它,那么,A对应的物理页是不会被分配的。
3,进程调用B=malloc(40K)以后,内存空间如图3
情况二:malloc 大于 128K 的内存,使用 mmap 分配(munmap 释放)

4,进程调用C=malloc(200K)以后,内存空间如图4
默认情况下,malloc函数分配内存,如果请求内存大于128K(可由M_MMAP_THRESHOLD选项调节),那就不是去推_edata指针了,而是利用mmap系统调用,从堆和栈的中间分配一块虚拟内存
这样子做主要是因为:
brk分配的内存需要等到高地址内存释放以后才能释放(例如,在B释放之前,A是不可能释放的,因为只有一个_edata 指针,这就是内存碎片产生的原因,什么时候紧缩看下面),而mmap分配的内存可以单独释放。
当然,还有其它的好处,也有坏处,再具体下去,有兴趣的同学可以去看glibc里面malloc的代码了。
5,进程调用D=malloc(100K)以后,内存空间如图5
6,进程调用free(C)以后,C对应的虚拟内存和物理内存一起释放

7,进程调用free(B)以后,如图7所示
B对应的虚拟内存和物理内存都没有释放,因为只有一个_edata指针,如果往回推,那么D这块内存怎么办呢?当然,B这块内存,是可以重用的,如果这个时候再来一个40K的请求,那么malloc很可能就把B这块内存返回回去了
8,进程调用free(D)以后,如图8所示
B和D连接起来,变成一块140K的空闲内存
9,默认情况下:
当最高地址空间的空闲内存超过128K(可由M_TRIM_THRESHOLD选项调节)时,执行内存紧缩操作(trim)。在上一个步骤free的时候,发现最高地址空闲内存超过128K,于是内存紧缩,变成图9所示
参考博客:https://www.cnblogs.com/dongzhiquan/p/5621906.html
malloc 底层实现及原理的更多相关文章
- 从底层谈WebGIS 原理设计与实现(三):WebGIS前端地图显示之根据地理范围换算出瓦片行列号的原理(转载)
从底层谈WebGIS 原理设计与实现(三):WebGIS前端地图显示之根据地理范围换算出瓦片行列号的原理 1.前言 在上一节中我们知道了屏幕上一像素等于实际中多少单位长度(米或经纬度)的换算方法, ...
- 从底层谈WebGIS 原理设计与实现(六):WebGIS中地图瓦片在Canvas上的拼接显示原理
从底层谈WebGIS 原理设计与实现(六):WebGIS中地图瓦片在Canvas上的拼接显示原理 作者:naaoveGI… 文章来源:naaoveGIS 点击数:1145 更新时间: ...
- 从底层谈WebGIS 原理设计与实现(五):WebGIS中通过行列号来换算出多种瓦片的URL 之在线地图
从底层谈WebGIS 原理设计与实现(五):WebGIS中通过行列号来换算出多种瓦片的URL 之在线地图 作者:naaoveGI… 文章来源:naaoveGIS 点击数:2063 更 ...
- 从底层谈WebGIS 原理设计与实现(四):WebGIS中通过行列号来换算出多种瓦片的URL 之离线地图
从底层谈WebGIS 原理设计与实现(四):WebGIS中通过行列号来换算出多种瓦片的URL 之离线地图 作者:naaoveGI… 文章来源:naaoveGIS 点击数:1759 更 ...
- 从底层谈WebGIS 原理设计与实现(二):探究本质,WebGIS前端地图显示之地图比例尺换算原理
从底层谈WebGIS 原理设计与实现(二):探究本质,WebGIS前端地图显示之地图比例尺换算原理 作者:naaoveGI… 文章来源:http://www.cnblogs.com/naaove ...
- 从底层谈WebGIS 原理设计与实现(一):开篇
从底层谈WebGIS 原理设计与实现(一):开篇 作者:naaoveGI… 文章来源:http://www.cnblogs.com/naaoveGIS/ 点击数:4773 更新时间: ...
- JUC回顾之-CyclicBarrier底层实现和原理
1.CyclicBarrier 字面意思是可循环(Cyclic)使用的屏障(Barrier).它要做的事情是让一组线程到达一个屏障(同步点)时被阻塞,直到最后一个线程到达屏障时候,屏障才会开门.所有被 ...
- HashMap底层结构、原理、扩容机制
https://www.jianshu.com/p/c1b616ff1130 http://youzhixueyuan.com/the-underlying-structure-and-princip ...
- 浅谈malloc()和free()工作原理
编程之路刚刚开始,错误难免,希望大家能够指出. malloc()和free()是我经常需要用到的函数,一般情况下,C程序使用malloc()在堆上分配内存,free()释放内存,两者的参数和返回值就 ...
随机推荐
- 面试题(10)之 leetcode-26
题目描述 解法一 对数组去重求数组长度,没有必要 /** * @param {number[]} nums * @return {number} */ var removeDuplicates = f ...
- module已经装了但仍提示找不到的解决方法
今天遇到的问题:(这里只是个例子) 解决方法: npm clean cache --force 删了node_modules 和 package-lock ,然后npm install 如果再不行,看 ...
- 13 装备的添加和移除(Unity3D)
本案例主要实现功能如下:1.创建UI界面,包含两个装备栏,四个武器选择栏以及显示人物的属性的文本框2.每一个装备都有自己的属性(AD/AP/AR/MP)3.人物也有自己的基础属性(AD/AP/AR/M ...
- 每天一点点之vue框架开发 - vue组件之间传值(父向子传值)
路由文件 { path: '/productListBase', name: 'productListLink', component: ProductListBase, redirect: '/pr ...
- PL/SQL表结构/数据的导出
1.表结构导出 方法一:在sql页面点击表名,进入表编辑页面,点击右下角“查看SQL”按钮,即可看到表结构 方法二:工具--导出用户对象 去掉所有者勾选项,即***.表名:用户名字在其他用户导入数据库 ...
- bzoj 4260REBXOR
什么什么trie树??呵呵呵,,,, 一直在困惑怎么处理哪连续一段最大..看了题解迷惑了好久.. 然后突然发现,是xor啊,,在trie树里找到以前得插入的前缀和,然后找到与现在前缀和每一位都不同的, ...
- swift 录音 AVAudioRecorder
2018年05月16日 15:22:44 msmwncx阅读数:548 https://blog.csdn.net/msmwncx/article/details/80336973 版权声明:本文为博 ...
- Upgrade to 17.1 from 17.0 problem:UnicodeEncodeError: 'ascii' codec can't encode character '\xc4' in position 50: ordinal not in range(128)
最近 gentoo 从 17.0 更新到 17.1, 需要手动进行升级配置,使用 unsymlink-lib -p --finish 这一步的时候报错,报错如下: /usr/lib/python-ex ...
- Day 11:静态导入、增强for循环、可变参数的自动装箱与拆箱
jdk1.5新特性-------静态导入 静态导入的作用: 简化书写. 静态导入可以作用一个类的所有静态成员. 静态导入的格式:import static 包名.类名.静态的成员: 静态导入要注意的 ...
- repr. str, ascii in Python
repr和str a="Hello" print(str(a)) print(repr(a)) 结果: Hello 'Hello' 可以看出,repr的结果中多了左右两个引号. r ...