大厂Java校招:内存满了,会发生什么?
前几天有位读者留言说面腾讯时被问了两个内存管理的问题先来说说第一个问题虚拟内存有什么作用第一由于每个进程都有自己的页表所以每个进程的虚拟内存空间就是相互独立的。进程也没有办法访问其他进程的页表所以这些页表是私有的。这就解决了多进程之间地址冲突的问题。第二页表里的页表项中除了物理地址之外还有一些标记属性的比特比如控制一个页的读写权限标记该页是否存在等。在内存访问方面操作系统提供了更好的安全性。然后今天主要是聊聊第二个问题「系统内存紧张时会发生什么」发车内存分配的过程是怎样的应用程序通过 malloc 函数申请内存的时候实际上申请的是虚拟内存此时并不会分配物理内存。当应用程序读写了这块虚拟内存CPU 就会去访问这个虚拟内存 这时会发现这个虚拟内存没有映射到物理内存 CPU 就会产生缺页中断进程会从用户态切换到内核态并将缺页中断交给内核的 Page Fault Handler 缺页中断函数处理。缺页中断处理函数会看是否有空闲的物理内存如果有就直接分配物理内存并建立虚拟内存与物理内存之间的映射关系。如果没有空闲的物理内存那么内核就会开始进行回收内存的工作回收的方式主要是两种直接内存回收和后台内存回收。后台内存回收kswapd在物理内存紧张的时候会唤醒 kswapd 内核线程来回收内存这个回收内存的过程异步的不会阻塞进程的执行。直接内存回收direct reclaim如果后台异步回收跟不上进程内存申请的速度就会开始直接回收这个回收内存的过程是同步的会阻塞进程的执行。如果直接内存回收后空闲的物理内存仍然无法满足此次物理内存的申请那么内核就会放最后的大招了 ——触发 OOM Out of Memory机制。OOM Killer 机制会根据算法选择一个占用物理内存较高的进程然后将其杀死以便释放内存资源如果物理内存依然不足OOM Killer 会继续杀死占用物理内存较高的进程直到释放足够的内存位置。申请物理内存的过程如下图哪些内存可以被回收系统内存紧张的时候就会进行回收内测的工作那具体哪些内存是可以被回收的呢主要有两类内存可以被回收而且它们的回收方式也不同。文件页File-backed Page内核缓存的磁盘数据Buffer和内核缓存的文件数据Cache都叫作文件页。大部分文件页都可以直接释放内存以后有需要时再从磁盘重新读取就可以了。而那些被应用程序修改过并且暂时还没写入磁盘的数据也就是脏页就得先写入磁盘然后才能进行内存释放。所以回收干净页的方式是直接释放内存回收脏页的方式是先写回磁盘后再释放内存。匿名页Anonymous Page应用程序通过 mmap 动态分配的堆内存叫作匿名页这部分内存很可能还要再次被访问所以不能直接释放内存它们回收的方式是通过 Linux 的 Swap 机制Swap 会把不常访问的内存先写到磁盘中然后释放这些内存给其他更需要的进程使用。再次访问这些内存时重新从磁盘读入内存就可以了。文件页和匿名页的回收都是基于 LRU 算法也就是优先回收不常访问的内存。LRU 回收算法实际上维护着 active 和 inactive 两个双向链表其中active_list活跃内存页链表这里存放的是最近被访问过活跃的内存页inactive_list不活跃内存页链表这里存放的是很少被访问非活跃的内存页越接近链表尾部就表示内存页越不常访问。这样在回收内存时系统就可以根据活跃程度优先回收不活跃的内存。活跃和非活跃的内存页按照类型的不同又分别分为文件页和匿名页。可以从 /proc/meminfo 中查询它们的大小比如# grep表示只保留包含active的指标忽略大小写 # sort表示按照字母顺序排序 [rootxiaolin ~]# cat /proc/meminfo | grep -i active | sort Active: 901456 kB Active(anon): 227252 kB Active(file): 674204 kB Inactive: 226232 kB Inactive(anon): 41948 kB Inactive(file): 184284 kB回收内存带来的性能影响在前面我们知道了回收内存有两种方式。一种是后台内存回收也就是唤醒 kswapd 内核线程这种方式是异步回收的不会阻塞进程。一种是直接内存回收这种方式是同步回收的会阻塞进程这样就会造成很长时间的延迟以及系统的 CPU 利用率会升高最终引起系统负荷飙高。可被回收的内存类型有文件页和匿名页文件页的回收对于干净页是直接释放内存这个操作不会影响性能而对于脏页会先写回到磁盘再释放内存这个操作会发生磁盘 I/O 的这个操作是会影响系统性能的。匿名页的回收如果开启了 Swap 机制那么 Swap 机制会将不常访问的匿名页换出到磁盘中下次访问时再从磁盘换入到内存中这个操作是会影响系统性能的。可以看到回收内存的操作基本都会发生磁盘 I/O 的如果回收内存的操作很频繁意味着磁盘 I/O 次数会很多这个过程势必会影响系统的性能整个系统给人的感觉就是很卡。下面针对回收内存导致的性能影响说说常见的解决方式。调整文件页和匿名页的回收倾向从文件页和匿名页的回收操作来看文件页的回收操作对系统的影响相比匿名页的回收操作会少一点因为文件页对于干净页回收是不会发生磁盘 I/O 的而匿名页的 Swap 换入换出这两个操作都会发生磁盘 I/O。Linux 提供了一个 /proc/sys/vm/swappiness 选项用来调整文件页和匿名页的回收倾向。swappiness 的范围是 0-100数值越大越积极使用 Swap也就是更倾向于回收匿名页数值越小越消极使用 Swap也就是更倾向于回收文件页。[rootxiaolin ~]# cat /proc/sys/vm/swappiness 0一般建议 swappiness 设置为 0默认就是 0这样在回收内存的时候会更倾向于文件页的回收但是并不代表不会回收匿名页。尽早触发 kswapd 内核线程异步回收内存如何查看系统的直接内存回收和后台内存回收的指标我们可以使用 sar -B 1 命令来观察图中红色框住的就是后台内存回收和直接内存回收的指标它们分别表示pgscank/s : kswapd(后台回收线程) 每秒扫描的 page 个数。pgscand/s: 应用程序在内存申请过程中每秒直接扫描的 page 个数。pgsteal/s: 扫描的 page 中每秒被回收的个数pgscankpgscand。如果系统时不时发生抖动并且在抖动的时间段里如果通过 sar -B 观察到 pgscand 数值很大那大概率是因为「直接内存回收」导致的。针对这个问题解决的办法就是可以通过尽早的触发「后台内存回收」来避免应用程序进行直接内存回收。什么条件下才能触发 kswapd 内核线程回收内存呢内核定义了三个内存阈值watermark也称为水位用来衡量当前剩余内存pages_free是否充裕或者紧张分别是页最小阈值pages_min页低阈值pages_low页高阈值pages_high这三个内存阈值会划分为四种内存使用情况如下图kswapd 会定期扫描内存的使用情况根据剩余内存pages_free的情况来进行内存回收的工作。图中绿色部分如果剩余内存pages_free大于 页高阈值pages_high说明剩余内存是充足的图中蓝色部分如果剩余内存pages_free在页高阈值pages_high和页低阈值pages_low之间说明内存有一定压力但还可以满足应用程序申请内存的请求图中橙色部分如果剩余内存pages_free在页低阈值pages_low和页最小阈值pages_min之间说明内存压力比较大剩余内存不多了。这时 kswapd0 会执行内存回收直到剩余内存大于高阈值pages_high为止。虽然会触发内存回收但是不会阻塞应用程序因为两者关系是异步的。图中红色部分如果剩余内存pages_free小于页最小阈值pages_min说明用户可用内存都耗尽了此时就会触发直接内存回收这时应用程序就会被阻塞因为两者关系是同步的。可以看到当剩余内存页pages_free小于页低阈值pages_low就会触发 kswapd 进行后台回收然后 kswapd 会一直回收到剩余内存页pages_free大于页高阈值pages_high。也就是说 kswapd 的活动空间只有 pages_low 与 pages_min 之间的这段区域如果剩余内测低于了 pages_min 会触发直接内存回收高于了 pages_high 又不会唤醒 kswapd。页低阈值pages_low可以通过内核选项 /proc/sys/vm/min_free_kbytes 该参数代表系统所保留空闲内存的最低限来间接设置。min_free_kbytes 虽然设置的是页最小阈值pages_min但是页高阈值pages_high和页低阈值pages_low都是根据页最小阈值pages_min计算生成的它们之间的计算关系如下pages_min min_free_kbytes pages_low pages_min*5/4 pages_high pages_min*3/2如果系统时不时发生抖动并且通过 sar -B 观察到 pgscand 数值很大那大概率是因为直接内存回收导致的这时可以增大 min_free_kbytes 这个配置选项来及早地触发后台回收然后继续观察 pgscand 是否会降为 0。增大了 min_free_kbytes 配置后这会使得系统预留过多的空闲内存从而在一定程度上降低了应用程序可使用的内存量这在一定程度上浪费了内存。极端情况下设置 min_free_kbytes 接近实际物理内存大小时留给应用程序的内存就会太少而可能会频繁地导致 OOM 的发生。所以在调整 min_free_kbytes 之前需要先思考一下应用程序更加关注什么如果关注延迟那就适当地增大 min_free_kbytes如果关注内存的使用量那就适当地调小 min_free_kbytes。NUMA 架构下的内存回收策略什么是 NUMA 架构再说 NUMA 架构前先给大家说说 SMP 架构这两个架构都是针对 CPU 的。SMP 指的是一种多个 CPU 处理器共享资源的电脑硬件架构也就是说每个 CPU 地位平等它们共享相同的物理资源包括总线、内存、IO、操作系统等。每个 CPU 访问内存所用时间都是相同的因此这种系统也被称为一致存储访问结构UMAUniform Memory Access。随着 CPU 处理器核数的增多多个 CPU 都通过一个总线访问内存这样总线的带宽压力会越来越大同时每个 CPU 可用带宽会减少这也就是 SMP 架构的问题。SMP 与 NUMA 架构为了解决 SMP 架构的问题就研制出了 NUMA 结构即非一致存储访问结构Non-uniform memory accessNUMA。NUMA 架构将每个 CPU 进行了分组每一组 CPU 用 Node 来表示一个 Node 可能包含多个 CPU 。每个 Node 有自己独立的资源包括内存、IO 等每个 Node 之间可以通过互联模块总线QPI进行通信所以也就意味着每个 Node 上的 CPU 都可以访问到整个系统中的所有内存。但是访问远端 Node 的内存比访问本地内存要耗时很多。NUMA 架构跟回收内存有什么关系在 NUMA 架构下当某个 Node 内存不足时系统可以从其他 Node 寻找空闲内存也可以从本地内存中回收内存。具体选哪种模式可以通过 /proc/sys/vm/zone_reclaim_mode 来控制。它支持以下几个选项0 默认值在回收本地内存之前在其他 Node 寻找空闲内存1只回收本地内存2只回收本地内存在本地回收内存时可以将文件页中的脏页写回硬盘以回收内存。4只回收本地内存在本地回收内存时可以用 swap 方式回收内存。在使用 NUMA 架构的服务器如果系统出现还有一半内存的时候却发现系统频繁触发「直接内存回收」导致了影响了系统性能那么大概率是因为 zone_reclaim_mode 没有设置为 0 导致当本地内存不足的时候只选择回收本地内存的方式而不去使用其他 Node 的空闲内存。虽然说访问远端 Node 的内存比访问本地内存要耗时很多但是相比内存回收的危害而言访问远端 Node 的内存带来的性能影响还是比较小的。因此zone_reclaim_mode 一般建议设置为 0。如何保护一个进程不被 OOM 杀掉呢在系统空闲内存不足的情况进程申请了一个很大的内存如果直接内存回收都无法回收出足够大的空闲内存那么就会触发 OOM 机制内核就会根据算法选择一个进程杀掉。Linux 到底是根据什么标准来选择被杀的进程呢这就要提到一个在 Linux 内核里有一个 oom_badness() 函数它会把系统中可以被杀掉的进程扫描一遍并对每个进程打分得分最高的进程就会被首先杀掉。进程得分的结果受下面这两个方面影响第一进程已经使用的物理内存页面数。第二每个进程的 OOM 校准值 oom_score_adj。它是可以通过 /proc/[pid]/oom_score_adj 来配置的。我们可以在设置 -1000 到 1000 之间的任意一个数值调整进程被 OOM Kill 的几率。函数 oom_badness() 里的最终计算方法是这样的// points 代表打分的结果 // process_pages 代表进程已经使用的物理内存页面数 // oom_score_adj 代表 OOM 校准值 // totalpages 代表系统总的可用页面数 points process_pages oom_score_adj*totalpages/1000用「系统总的可用页面数」乘以 「OOM 校准值 oom_score_adj」再除以 1000最后再加上进程已经使用的物理页面数计算出来的值越大那么这个进程被 OOM Kill 的几率也就越大。每个进程的 oom_score_adj 默认值都为 0所以最终得分跟进程自身消耗的内存有关消耗的内存越大越容易被杀掉。我们可以通过调整 oom_score_adj 的数值来改成进程的得分结果如果你不想某个进程被首先杀掉那你可以调整该进程的 oom_score_adj从而改变这个进程的得分结果降低该进程被 OOM 杀死的概率。如果你想某个进程无论如何都不能被杀掉那你可以将 oom_score_adj 配置为 -1000。我们最好将一些很重要的系统服务的 oom_score_adj 配置为 -1000比如 sshd因为这些系统服务一旦被杀掉我们就很难再登陆进系统了。但是不建议将我们自己的业务程序的 oom_score_adj 设置为 -1000因为业务程序一旦发生了内存泄漏而它又不能被杀掉这就会导致随着它的内存开销变大OOM killer 不停地被唤醒从而把其他进程一个个给杀掉。参考资料https://time.geekbang.org/column/article/277358https://time.geekbang.org/column/article/75797https://www.jianshu.com/p/e40e8813842f总结内核在给应用程序分配物理内存的时候如果空闲物理内存不够那么就会进行内存回收的工作主要有两种方式后台内存回收在物理内存紧张的时候会唤醒 kswapd 内核线程来回收内存这个回收内存的过程异步的不会阻塞进程的执行。直接内存回收如果后台异步回收跟不上进程内存申请的速度就会开始直接回收这个回收内存的过程是同步的会阻塞进程的执行。可被回收的内存类型有文件页和匿名页文件页的回收对于干净页是直接释放内存这个操作不会影响性能而对于脏页会先写回到磁盘再释放内存这个操作会发生磁盘 I/O 的这个操作是会影响系统性能的。匿名页的回收如果开启了 Swap 机制那么 Swap 机制会将不常访问的匿名页换出到磁盘中下次访问时再从磁盘换入到内存中这个操作是会影响系统性能的。文件页和匿名页的回收都是基于 LRU 算法也就是优先回收不常访问的内存。回收内存的操作基本都会发生磁盘 I/O 的如果回收内存的操作很频繁意味着磁盘 I/O 次数会很多这个过程势必会影响系统的性能。针对回收内存导致的性能影响常见的解决方式。设置 /proc/sys/vm/swappiness调整文件页和匿名页的回收倾向尽量倾向于回收文件页设置 /proc/sys/vm/min_free_kbytes调整 kswapd 内核线程异步回收内存的时机设置 /proc/sys/vm/zone_reclaim_mode调整 NUMA 架构下内存回收策略建议设置为 0这样在回收本地内存之前会在其他 Node 寻找空闲内存从而避免在系统还有很多空闲内存的情况下因本地 Node 的本地内存不足发生频繁直接内存回收导致性能下降的问题在经历完直接内存回收后空闲的物理内存大小依然不够那么就会触发 OOM 机制OOM killer 就会根据每个进程的内存占用情况和 oom_score_adj 的值进行打分得分最高的进程就会被首先杀掉。我们可以通过调整进程的 /proc/[pid]/oom_score_adj 值来降低被 OOM killer 杀掉的概率。完

相关新闻

Kioxia开始提供面向下一代移动应用的UFS 5.0嵌入式闪存设备样品

Kioxia开始提供面向下一代移动应用的UFS 5.0嵌入式闪存设备样品

更高的接口速度助力智能手机实现高性能设备端AI功能 全球存储解决方案领域的领军企业Kioxia Corporation今日宣布,已开始出货兼容下一代UFS标准UFS 5.0的嵌入式闪存评估样品(1),该标准目前正由JEDEC制定。(2) UFS 5.0是JEDEC正在开发的嵌入式闪存新标准…

2026/5/17 3:31:53 阅读更多 →
工业大数据平台怎么选?全球排行榜与典型案例解析

工业大数据平台怎么选?全球排行榜与典型案例解析

工业大数据平台怎么选?全球排行榜与典型案例解析工业大数据作为数字经济时代的核心生产要素,正日益成为推动全球制造业转型升级的关键力量。工业大数据排行榜的出现,不仅反映了企业在数据采集、处理、应用等方面的综合能力,更揭示…

2026/7/5 15:21:08 阅读更多 →
RobustVisRAG Causality-Aware Vision-Based Retrieval-Augmented Generation under Visual Degradations

RobustVisRAG Causality-Aware Vision-Based Retrieval-Augmented Generation under Visual Degradations

RobustVisRAG: Causality-Aware Vision-Based Retrieval-Augmented Generation under Visual Degradations Authors: I-Hsiang Chen, Yu-Wei Liu, Tse-Yu Wu, Yu-Chien Chiang, Jen-Chien Yang, Wei-Ting Chen Deep-Dive Summary: 这篇论文介绍了一个名为 RobustVisRAG 的框架…

2026/7/6 2:10:21 阅读更多 →

最新新闻

SONiC 2024 容器化架构解析:10个核心Docker容器如何驱动网络转发

SONiC 2024 容器化架构解析:10个核心Docker容器如何驱动网络转发

SONiC 2024容器化架构深度解析:10个核心容器如何构建下一代云网络1. 现代网络操作系统的容器化革命当微软在2016年首次开源SONiC项目时,很少有人能预料到这个基于Linux的网络操作系统会彻底改变数据中心网络的构建方式。八年后的今天,SONiC已…

2026/7/6 2:55:56 阅读更多 →
QooBot:全栈开源的仿生人操作系统——软硬一体,自由制造

QooBot:全栈开源的仿生人操作系统——软硬一体,自由制造

QooBot:全栈开源的仿生人操作系统——软硬一体,自由制造 摘要:QooBot 是一个面向仿生人的开源全栈生态,涵盖从机械图纸、电路设计到操作系统、AI 算法的完整技术栈。本文从架构全景、大脑核心、推理引擎、开发者生态等维度全面解读…

2026/7/6 2:53:55 阅读更多 →
可变级数LC无源自均压海量级联多电平拓扑机理研究——代替传统LCC/MMC的新一代特高压直流逆变架构

可变级数LC无源自均压海量级联多电平拓扑机理研究——代替传统LCC/MMC的新一代特高压直流逆变架构

可变级数LC无源自均压海量级联多电平拓扑机理研究——取代传统LCC/MMC的新一代特高压直流逆变架构 ----------作者:杨连江 摘要 针对我国特高压直流输电现有两大技术体系(LCC电网换相直流、MMC柔性直流)存在的底层机理缺陷,本文提…

2026/7/6 2:53:55 阅读更多 →
卡梅德生物技术快报| KM13 辅助噬菌体的天然 VHH 噬菌体文库全套构建流程与数据验证

卡梅德生物技术快报| KM13 辅助噬菌体的天然 VHH 噬菌体文库全套构建流程与数据验证

一、提出问题:实验室自建纳米抗体文库常遇四大工程化痛点 食品检测实验室自主构建 VHH 噬菌体文库时,普遍存在工程化落地难题:其一,普通单轮 PCR 扩增 VHH 基因存在大量缺失,文库多样性不足;其二&#xff…

2026/7/6 2:51:55 阅读更多 →
Variance Reduction with Baseline 补充 - 加基线使得方差降低

Variance Reduction with Baseline 补充 - 加基线使得方差降低

什么叫基线 基线就是一个只和当前状态s有关、和动作a无关的数值 b(s),用来做 “参考平均分”假设某状态s平均长期收益 b(s)10 某条轨迹 G_t18:A_t18-108>0,动作比平均更好,加大该动作概率 某条轨迹 G_t3:A_t3-10-7…

2026/7/6 2:51:55 阅读更多 →
MP1584 降压电源 PCB 布局 5 大要点:实测 SW 节点尖峰降低 60%

MP1584 降压电源 PCB 布局 5 大要点:实测 SW 节点尖峰降低 60%

MP1584降压电源PCB布局实战:5大核心技巧让SW节点尖峰直降60%作为一名长期奋战在电源设计一线的工程师,我深知PCB布局对开关电源性能的决定性影响。今天我们就以MP1584这款经典降压芯片为例,通过实测数据揭示那些手册上不会告诉你的布局奥秘。…

2026/7/6 2:49:55 阅读更多 →

日新闻

H2 与 MySQL 单元测试兼容性:5 个关键 SQL 语句差异与规避方案

H2 与 MySQL 单元测试兼容性:5 个关键 SQL 语句差异与规避方案

H2与MySQL单元测试兼容性:5个关键SQL语句差异与规避方案1. 单元测试中的数据库兼容性挑战在Java开发领域,单元测试是保证代码质量的重要环节。当应用涉及数据库操作时,测试环境的搭建往往成为开发者的痛点。H2数据库因其轻量级、内存模式和快…

2026/7/6 0:01:17 阅读更多 →
Windows任务栏终极清理指南:用RBTray一键隐藏窗口到系统托盘

Windows任务栏终极清理指南:用RBTray一键隐藏窗口到系统托盘

Windows任务栏终极清理指南:用RBTray一键隐藏窗口到系统托盘 【免费下载链接】rbtray A fork of RBTray from http://sourceforge.net/p/rbtray/code/. 项目地址: https://gitcode.com/gh_mirrors/rb/rbtray 你是否厌倦了Windows任务栏上密密麻麻的图标&…

2026/7/6 0:01:17 阅读更多 →
Visual C++ 运行时库一键安装终极指南:告别DLL缺失烦恼

Visual C++ 运行时库一键安装终极指南:告别DLL缺失烦恼

Visual C 运行时库一键安装终极指南:告别DLL缺失烦恼 【免费下载链接】vcredist AIO Repack for latest Microsoft Visual C Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist 你是否曾经遇到过这样的情况:下载了…

2026/7/6 0:05:19 阅读更多 →

周新闻

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱,支持下载视频、番剧等等各类资源 项目地址: https://gitcode.com/GitHub_Trending/bilit/BiliTools …

2026/7/5 0:03:34 阅读更多 →
威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型的陌生现状在忙碌疲惫的一天里,参与了关于混合后量子密码学的讨论,应付端点攻击找茬的人,还参与留言板讨论后,发现“威胁模型”对多数人仍是陌生概念,且多被当作时髦用语。有趣的相关画作有一幅由 Embyr 创作的…

2026/7/5 0:03:34 阅读更多 →
渗透测试入门指南:从零基础到实战环境搭建

渗透测试入门指南:从零基础到实战环境搭建

1. 从“看热闹”到“入门”:我理解的渗透测试到底是什么?每次看到新闻里说某个大公司的数据被“黑”了,或者某个网站被攻击导致服务瘫痪,你是不是和我一样,心里会冒出两个念头:一是“这黑客真厉害”&#x…

2026/7/5 0:07:38 阅读更多 →

月新闻