【Linux内核】内存管理——内存回收机制
转载请注明: https://www.cnblogs.com/Ethan-Code/p/16626560.html
内存回收的方式
前文提到malloc的内存分配方式,malloc申请的是虚拟内存,只有在程序去访问时,才会触发缺页异常进入内核态,在缺页中断函数中建立物理内存映射。
如果物理内存充足,则直接建立页框与页的映射。当物理内存不足时,内核会进行物理内存回收,内存回收的方式主要有:
- 后台内存回收(kswapd)
- 直接内存回收(direct reclaim)
- OOM机制(Out of Memory)
三种内存回收方式按内存的紧缺程度递进。
后台内存回收——kswapd
本小节提到的内存主要针对物理内存
kswapd 是一个内核线程,在内存不足时负责在后台进行内存回收,这个过程发生在后台,因此是异步发生,不会阻塞进程。
内核对的容量设置了三个阈值:
- 页最小阈值(pages_min);
- 页低阈值(pages_low);
- 页高阈值(pages_high);
当内存大于 pages_low 时,表示此时系统内存足够,不会进行内存回收。
当内存小于 pages_low 时,表示此时内存存在压力,会触发 kswapd0 进行后台内存回收,直到 pages_high 为止。
当内存小于 pages_min 时,表示此时用户内存耗尽,会触发直接内存回收,进程被阻塞。
如果要调整 kswapd 的触发时机,需要修改 pages_low 的值,而**pages_low的值由pages_min计算,因此需要修改pages_min**。
内核选项
/proc/sys/vm/min_free_kbytes
可以设置 pages_min
因此可以通过 min_free_kbytes 的值来修改内存水位阈值。
直接内存回收
在进程申请并访问内存时,如果此时内存可用page数小于pages_min,不足以进行内存分配建立映射关系。
此时会触发直接内存回收,阻塞进程的同时开始回收内存,因此这种内存回收方式是同步的。
对进程的阻塞会造成长时间的延迟,系统CPU利用率会升高,系统负荷会增大,因此要尽量避免直接内存回收。
OOM——Out of Memory
如果直接内存回收之后,系统的剩余空闲内存还不足以进行内存分配,则会进一步触发OOM机制。
OOM Killer 机制会根据算法选择并kill掉一个占用物理内存较高的进程,以便释放内存资源,如果物理内存依然不足,OOM Killer 会继续杀死占用物理内存较高的进程,直到释放足够的内存位置。
Linux 内核里有一个 oom_badness()
函数,它会把系统中可以被杀掉的进程扫描一遍,并对每个进程打分,得分最高的进程就会被首先杀掉。
进程的得分一般由其占用的物理内存页框数量决定。
函数 oom_badness() 计算方法:points = process_pages + oom_score_adj*totalpages/1000
变量 | 含义 |
---|---|
points | 打分的结果 |
process_pages | 进程已经使用的物理内存页面数 |
oom_score_adj | 进程的 OOM 校准值 一般为0 |
totalpages | 系统总的可用页面数 |
可以通过设置 OOM校准值 即 修改 /proc/[pid]/oom_score_adj
的值来调整OOM,从而改变这个进程的得分结果,降低该进程被 OOM 杀死的概率。
oom_score_adj的设置范围是[-1000,1000]
内存回收时机的性能影响
sar -B 1
命令可以观察内存回收情况:
pgscank/s : kswapd 每秒扫描的 page 个数。
pgscand/s: 应用程序在内存申请过程中每秒直接扫描的 page 个数。
pgsteal/s: 扫描的 page 中每秒被回收的个数(pgscank+pgscand)。
当 pages_low 设置不合理时,kswapd后台回收内存不及时,申请内存会经常触发直接内存回收,pgscand/s 数值会比较大,在性能上看会造成系统抖动。可以通过适当增大 min_free_kbytes,提前触发 kswapd 内核线程,避免直接内存回收。
修改 min_free_kbytes 的性能影响:
- min_free_kbytes 比较小,系统预留较小的空闲内存,因此大部分内存都给进程使用。但是会导致kswapd回收不及时,触发直接内存回收,阻塞进程。
- min_free_kbytes 比较大,系统则会预留更多空闲内存,在提升性能的同时会减少应用进程的可用内存,降低内存利用率,是空间换时间的方式。
- min_free_kbytes 特别大,极端情况下接近总内存大小,只有很少的内存可以使用,可能会频繁触发OOM。
内存回收的具体过程——文件页和匿名页
上述提到的两种内存回收方式(kswapd和直接回收)主要回收的对象是内存中的文件页和匿名页。
- 文件页(File-backed Page):内核缓存的磁盘数据(Buffer)和内核缓存的文件数据(Cache)都叫作文件页。
- 匿名页(Anonymous Page):这部分内存没有实际载体,如堆、栈数据等,不像文件缓存有硬盘文件这样一个载体。
文件页和匿名页的回收都是基于LRU算法(最近最少使用算法)。
在Linux内核中LRU算法维护两条双向链表:active链表 和 inactive链表,通过PG_active
位状态判断是否活跃,通过PG_referenced
位状态判断是否访问过。通过这两个页面标识符决定如何在两个链表之间移动页面。
实际上,对链表的并发访问需要使用自旋锁避免冲突,对此内核还提供了LRU缓存机制,只有当要插入到这两条链表的页面达到一定数量时才会一次性添加到相应链表中,从而降低锁的竞争,提升系统性能。
内存不足时,内核会优先回收 inactive链表 的尾部页面。
- 文件页回收:如果这个文件页是干净的(clean),则直接释放内存,不影响系统性能。如果是脏页(dirty),则需要先写入磁盘,再释放内存,这个过程会发生IO操作,因此会影响系统性能。
- 匿名页回收:因为这部分内存可能还会使用到,因此不能直接释放。如果开启了swap机制,则会先把内存存入磁盘中,等到需要的时候再从磁盘中读出。这个过程会发生IO操作,因此会影响系统性能。
可以看出,除了回收干净文件页,其他内存页回收基本都会发生磁盘IO,对系统的性能是会影响的。
因此,对于内存回收,应该设置根据需求设置合适的参数,从而调整kswapd的内存回收时机,调整直接内存回收的频率,减少OOM机制的触发,提高系统的性能和稳定性。
好文推荐:https://xiaolincoding.com/os/3_memory/mem_reclaim.html
关于LRU可以参考:https://www.cnblogs.com/muahao/p/10109712.html
【Linux内核】内存管理——内存回收机制相关推荐
- Linux内核如何管理内存
在学习了进程的 虚拟地址布局 之后,让我们回到内核,来学习它管理用户内存的机制.这里再次使用 Gonzo: Linux kernel mm_struct Linux 进程在内核中是作为进程描述符 ta ...
- JVM内存管理及GC机制
转载自:http://blog.csdn.net/suifeng3051/article/details/48292193 一.概述 Java GC(Garbage Collection,垃圾收集,垃 ...
- java堆是gc管理_JVM内存管理及GC机制
一.概述 JavaGC(Garbage Collection,垃圾收集,垃圾回收)机制,是Java与C++/C的主要区别之一,作为Java开发者,一般不需要专门编写内存回收和垃圾清理代码,对内存泄露和 ...
- 【Linux 内核 内存管理】RCU 机制 ② ( RCU 机制适用场景 | RCU 机制特点 | 使用 RCU 机制保护链表 )
文章目录 一.RCU 机制适用场景 二.RCU 机制特点 三.使用 RCU 机制保护链表 一.RCU 机制适用场景 在上一篇博客 [Linux 内核 内存管理]RCU 机制 ① ( RCU 机制简介 ...
- 【Linux 内核 内存管理】RCU 机制 ① ( RCU 机制简介 | RCU 机制的优势与弊端 | RCU 机制的链表应用场景 )
文章目录 一.RCU 机制 二.RCU 机制的优势与弊端 三.RCU 机制的链表应用场景 一.RCU 机制 RCU , 英文全称是 " Read-Copy-Update " , 对 ...
- 详细讲解Linux内核源码内存管理(值得收藏)
Linux的内存管理是一个非常复杂的过程,主要分成两个大的部分:内核的内存管理和进程虚拟内存.内核的内存管理是Linux内存管理的核心,所以我们先对内核的内存管理进行简介. 一.物理内存模型 物理内存 ...
- Linux内存管理:分页机制
<Linux内存管理:内存描述之内存节点node> <Linux内存管理:内存描述之内存区域zone> <Linux内存管理:内存描述之内存页面page> < ...
- linux内核工程导论,Linux内核工程导论——内存管理(3)
Linux内核工程导论--内存管理(三) 用户端内核内存参数调整 /proc/sys/vm/ (需要根据内核版本调整) 交换相关 swap_token_timeout Thisfile contain ...
- Linux内核高端内存
Linux内核地址映射模型 x86 CPU采用了段页式地址映射模型.进程代码中的地址为逻辑地址,经过段页式地址映射后,才真正访问物理内存. 段页式机制如下图. Linux内核地址空间划分 通常32 ...
- 纯干货,linux内存管理——内存管理架构(建议收藏)
一.内存管理架构 内存管理子系统架构可以分为:用户空间.内核空间及硬件部分3个层面,具体结构如下所示: 1.用户空间:应用程序使用malloc()申请内存资源/free()释放内存资源. 2.内核空间 ...
最新文章
- Cocos2d-x 生成真正的随机数
- javacript实现不被浏览器拦截打开新窗口
- android相对布局代码,Android基础_3 Activity相对布局(示例代码)
- mysql collate
- java js倒计时_Java实现倒计时的方法详解
- C语言程序设计谭浩强版 六
- 充电头PD协议和QC协议的理解
- 正则表达式及bash脚本(一)
- 一个公司的开发流程总结
- 汽车租赁系统(2)-完成登录功能
- FPGA 学习笔记:Vivado 2020.2 MicroBlaze MIG 测试 DDR3 篇尾
- Automa 和看小说脚本
- tkinter实现图片自适应
- 最新v4.2版本CRMEB商城API接口文档标准版后台(一)
- 输油管道问题(线性时间解决)
- java酒店管理系统课程设计_JSP酒店管理系统课程设计.doc
- 学编程有哪些好点的网站呢?
- 【Tools】如何在word/wps中添加代码,并且保持源代码风格
- 草图大师可以导出什么格式_草图是什么,它是为谁准备的?
- Linux-虚拟机中大小写不停切换问题解决办法
热门文章
- Python使用Treeview制作表格(二)
- 计算机网络:CSMA/CA协议
- 微服务(四)——统一网关
- 为什么要清除浮动,目的是什么?
- 软件项目管理经验总结
- 基于STM32设计的遥控小车(手机APP+GPS+温湿度+ESP8266)
- 基于javaweb的旅游管理系统(java+jsp+html5+bootstrap+servlet+mysql)
- Python中字典创建、遍历、添加
- 密码 加盐处理 是什么
- Spring Data JDBC自动生成的增删改查CRUD分页、排序SQL语句非常简洁没有多余的SQL