当一个进程发生缺页中断的时候,进程会陷入内核态,执行以下操作: 
1、检查要访问的虚拟地址是否合法 
2、查找/分配一个物理页 
3、填充物理页内容(读取磁盘,或者直接置0,或者啥也不干) 
4、建立映射关系(虚拟地址到物理地址) 
重新执行发生缺页中断的那条指令 
如果第3步,需要读取磁盘,那么这次缺页中断就是majflt,否则就是minflt。 

内存分配的原理

从操作系统角度来看,进程分配内存有两种方式,分别由两个系统调用完成:brk和mmap(不考虑共享内存)。

1、brk是将数据段(.data)的最高地址指针_edata往高地址推;

2、mmap是在进程的虚拟地址空间中(堆和栈中间,称为文件映射区域的地方)找一块空闲的虚拟内存

     这两种方式分配的都是虚拟内存,没有分配物理内存在第一次访问已分配的虚拟地址空间的时候,发生缺页中断,操作系统负责分配物理内存,然后建立虚拟内存和物理内存之间的映射关系。


在标准C库中,提供了malloc/free函数分配释放内存,这两个函数底层是由brk,mmap,munmap这些系统调用实现的。

下面以一个例子来说明内存分配的原理:

情况一、malloc小于128k的内存,使用brk分配内存,将_edata往高地址推(只分配虚拟空间,不对应物理内存(因此没有初始化),第一次读/写数据时,引起内核缺页中断,内核才分配对应的物理内存,然后虚拟地址空间建立映射关系),如下图:


1、进程启动的时候,其(虚拟)内存空间的初始布局如图1所示。
其中,mmap内存映射文件是在堆和栈的中间(例如libc-2.2.93.so,其它数据文件等),为了简单起见,省略了内存映射文件。
_edata指针(glibc里面定义)指向数据段的最高地址。 
2、
进程调用A=malloc(30K)以后,内存空间如图2:
malloc函数会调用brk系统调用,将_edata指针往高地址推30K,就完成虚拟内存分配。
      你可能会问:只要把_edata+30K就完成内存分配了?
事实是这样的,_edata+30K只是完成虚拟地址的分配,A这块内存现在还是没有物理页与之对应的,等到进程第一次读写A这块内存的时候,发生缺页中断,这个时候,内核才分配A这块内存对应的物理页。也就是说,如果用malloc分配了A这块内容,然后从来不访问它,那么,A对应的物理页是不会被分配的。 
3、
进程调用B=malloc(40K)以后,内存空间如图3。

情况二、malloc大于128k的内存,使用mmap分配内存,在堆和栈之间找一块空闲内存分配(对应独立内存,而且初始化为0),如下图:

4、进程调用C=malloc(200K)以后,内存空间如图4:
默认情况下,malloc函数分配内存,如果请求内存大于128K(可由M_MMAP_THRESHOLD选项调节),那就不是去推_edata指针了,而是利用mmap系统调用,从堆和栈的中间分配一块虚拟内存。
      这样子做主要是因为::
      brk分配的内存需要等到高地址内存释放以后才能释放(例如,在B释放之前,A是不可能释放的,这就是内存碎片产生的原因,什么时候紧缩看下面),而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所示。

malloc原理和内存碎片相关推荐

  1. 详解malloc,calloc,realloc原理及其模拟实现

    malloc原理 malloc它有一个将可用的内存块连接为一个长长的列表的所谓空闲链表.调用malloc函数时,它沿连接表寻找一个大到足以满足 用户请求所需要的内存块.然后,将该内存块一分为二(一块的 ...

  2. Linux内存背后的那些神秘往事

    Linux内存背后的那些神秘往事 作者:大白斯基(公众号:后端研究所) 转自:https://mp.weixin.qq.com/s/l_YdpyHht5Ayvrc7LFZNIA 前言 大家好,我的朋友 ...

  3. C语言之动态内存管理

    目录 为什么存在动态内存管理 动态内存函数 malloc和free函数 calloc realloc 动态内存的常见错误 1对空指针的解引用操作 2对动态开辟空间的越界访问 3使用free来释放非动态 ...

  4. 【项目】实现一个mini的tcmalloc(高并发内存池)

    文章目录 tcmalloc 池化技术 内存池解决的问题 malloc的相关知识 玩具malloc原理简述 ptmalloc简述 铺垫 chunk 线程安全 小结 实现一个定长内存池 原理 代码 测试 ...

  5. 嵌入式笔试/面试概念

    嵌入式笔试概念 [硬件接口类型] *Nor flash and nand flash 的区别* *常用总线对比表格* *I2C通信协议* *SPI通信协议* *UART通信协议* [常见笔试考点] * ...

  6. 取经之路就在眼前--面经备战

    Android 面经收集大全 注意: 本文是通过阅读大量的博文以及其他论坛的精彩好文简化版随手录,如有侵权马上删除! 持续更新~~ 文字多,难免有些错别字,最近时间忙,后续尽快更改,望谅解 文章目录 ...

  7. 有,51高俊峰 Linux高级架构师​

    作者徽:822135616 在编程中,为了避免由于频繁的malloc/free产生内存碎片,通常会在程序中实现自己的内存管理模块,即内存池.内存池的原理:程序启动时为内存池申请一块较大的内存,在程序中 ...

  8. 2022年嵌入式秋招题目及解答

    2022年嵌入式秋招题目及解答 1 ARM体系结构.总线.各种外设.微机原理 ARM的中断处理流程,以及每个阶段做什么事(中断触发到返回的具体行为): 中断上下文 中断嵌套如何实现(NVIC相关) 两 ...

  9. 一个高级软件工程师面试被问的问题

    使用new和malloc如何解决内存碎片问题? 多进程间通信几种方式,你用过几种方式? 线程间通信,用过几种方式 分不同的场景,适合用哪种通信方式 内存管理,如果让你来实现.你会怎么去设计.内存池实现 ...

最新文章

  1. PyInstaller将python脚本打包成exe可执行程序
  2. c#中泛型参数与object参数导致重写无效。
  3. Ubuntu中NS2安装详细教程
  4. php 显示当前年月日时分秒,php 获取当前前后年、月、星期、日、时分秒的时间...
  5. 红旗Linux网卡绑定,Linux bonding 之balance-alb 原理介绍及其实现
  6. pandas绘图_pandas与seaborn可视化对比小案例
  7. [每日一题] 11gOCP 1z0-053 :2013-10-1 persistent lightweight jobs...........................11
  8. 计算机组成原理内存模块,计算机组成原理
  9. 详解阿里云第六代增强型实例,性能强劲,百万IOPS加持
  10. Android StickHeaderRecyclerView - 让recyclerview头部固定
  11. matlab图像加椒盐噪声,用matlab给图像加高斯噪声和椒盐噪声(不调用imnoise函数)...
  12. C盘Administrator中 .m2/repository里面是什么
  13. lzg_ad:XPE数据库组件
  14. 怎样用c语言编出旗子的图案,三色棋解法的C语言实现
  15. 畅享9能改鸿蒙,华为畅享9 root教程_畅享9卡刷root包来获取root权限的方法
  16. Flutter 调用百度地图APP实现位置搜索、路线规划
  17. 实践中的重构19_脱裤子放屁
  18. EXCEL描述统计输出详解:标准误、置信度、偏度、峰度和JB检验
  19. 电脑中存储的文件怎么打印出来?
  20. Spring boot实现代理服务器

热门文章

  1. java 64位 默认分配内存大小_查看你机器中Java程序堆内存的默认初始大小和最大大小...
  2. python queue_Python-Queue 入门
  3. velodyne显示点云中grid的单位_led显示屏怎么选择点间距
  4. 《深度探索C++对象模型》--1 关于对象
  5. 一看你就懂,超详细java中的ClassLoader详解
  6. 69道Java Spring 面试笔试题
  7. 聊聊clean code
  8. Spring松耦合的实现
  9. Linux 的文件权限与目录配置
  10. 控制iOS的导航栏和状态栏的样式