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()释放内存,两者的参数和返回值就 ...
随机推荐
- eclipse中svn重新设置账户
查看svn版本:windows > preference > Team > SVN 1.如果svn插件是svnkit版 只需找到.keyring文件,一般目录是:eclipse安装目 ...
- rsync错误
rsync error:No route to host rsync服务端开启的iptables防火墙 [root@nfs01 tmp]# rsync -avz /etc/hosts rsync_ba ...
- spring学习第7天(PCD以及切点表达式)
1.PCD(PointCutDesigner) spring的aop只针对方法进行aop代理,而apectj联盟的aop比之更加强大,还可以针对字段等进行切面编程 1.1:execution,用的最多 ...
- GS 原理及破解 《0day安全》
1.原理: 在main函数之前,会调用__security_init_cookie函数(win10,vs2017,release,x86): 进入__security_init_cookie函数内部: ...
- 前端基础之AJAX
AJAX 什么是AJAX,简单来说就是利用JavaScript天生异步的特性,使用异步请求后台数据,从而达到不刷新网页也能局部更新页面的效果. 原生AJAX JavaScript中的AJAX依赖于XM ...
- HDU - 6025 Coprime Sequence(前缀gcd+后缀gcd)
题意:去除数列中的一个数字,使去除后数列中所有数字的gcd尽可能大. 分析:这个题所谓的Coprime Sequence,就是个例子而已嘛,题目中没有任何语句说明给定的数列所有数字gcd一定为1→_→ ...
- 51nod 1105:第K大的数
1105 第K大的数 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题 收藏 关注 数组A和数组B,里面都有n个整数.数组C共有n^2个整数,分别是A[0] * ...
- 不得了的try catch
try catch:几乎所有语言都有这个语句 try { //可能会导致错误的代码 } catch (error) { //在错误发生时怎么处理 }finally { //即使报错始终执行 } 1. ...
- 17 —— 服务端渲染 —— art-template
一,前端渲染数据 的弊端 仿 apache 服务器与客户端的几次交互: 1,加载静态页面 2,加载静态资源 3,发送 ajax 请求 ,接收请求并处理返回 . 4,前端浏览器接收数据循环遍历. 存在的 ...
- 剑指offer_1.24_Day_4
构建乘积数组 给定一个数组A[0,1,...,n-1],请构建一个数组B[0,1,...,n-1],其中B中的元素B[i]=A[0]*A[1]*...*A[i-1]*A[i+1]*...*A[n-1] ...