首页/新闻资讯/正文详情

Linux vm.swappiness 参数详解:从原理到实战的内存回收调优指南

发布时间:2026/9/24 22:00:23 来源:云帆数科 栏目:资讯中心
Linux vm.swappiness 参数详解:从原理到实战的内存回收调优指南
做Linux服务器调优这些年我几乎每接手一台机器都会先看一眼vm.swappiness。很多人一看到swap使用量上涨就开始紧张要么急着把参数改成0要么直接下结论说内存不够用。这话只对了一半swap活跃不一定代表性能要崩vm.swappiness设成0也不是所有场景的万能答案。这篇内容我会把这个参数从原理到实操、从单机到容器环境完整拆开来讲顺便把我踩过的一些坑也一并列出来。无论你是刚入门想搞懂Linux内存回收逻辑的新手还是已经在生产环境调过很多次内核参数的老手这篇都值得你花几分钟过一遍。1. 先搞清楚 vm.swappiness 管的是什么1.1 内存回收时的一次“判断题”要理解vm.swappiness得先知道Linux内核在什么时候会用到它。运行中的进程不断申请内存page cache也会吃掉大量内存来缓存磁盘文件。当空闲内存越来越少、降到某个水位线watermark以下之后内核的kswapd线程会被唤醒开始在内存页里做回收。回收不是随便拆东墙补西墙它面对的主要是两类页文件页file-backed pages来自磁盘文件或文件系统的缓存回收时如果是干净页直接丢弃以后要用再回磁盘读如果是脏页得先写回磁盘再丢弃。匿名页anonymous pages进程堆、栈、匿名mmap等没有文件对应的内存页想回收就得先把内容写到swap设备上也就是“换出”以后访问时再从swap里“换入”。这道选择题就是vm.swappiness参与的地方。内核在计算匿名页回收优先级和文件页回收优先级的时候会用 swappiness 作为权重。值越高匿名页越“愿意”被回收也就是系统更偏向把进程占用的内存换到swap去从而留下更多物理内存给page cache值越低系统越优先回收文件页尽量不把进程内存折腾进swap。很多资料把vm.swappiness说成“系统使用swap的倾向”这个说法方向对但不够精确。它实际控制的是匿名页和文件页之间如何取舍不是简单的“是否使用swap”开关。1.2 默认60不是拍脑袋它是个相对均衡的起点几乎每个发行版默认都是vm.swappiness60。这个值想做的是给文件缓存和匿名页一个相对公平的竞争机会。文件缓存对读密集负载很重要反复读同一个数据库文件时page cache命中能让延迟低很多匿名页则是正在运行进程的直接内存换出和换入都有代价。60这个值在多数普通桌面和通用服务器上表现得比较均衡不会让系统特别偏向某一边。但“均衡”不等于“最优”。生产环境负载类型千差万别有些机器主要跑数据库有些是静态资源Web服务有些跑批任务它们对内存回收的敏感性完全不一样。默认值只能说安全不能说合适。这也是为什么我们需要针对自己场景去调它的原因。1.3 0和100的真实含义别把倾向当百分比这里必须澄清一个高频误区swappiness100不是说“系统会用掉100%的内存去做交换”swappiness10也不代表“只有10%的内存会被交换”。它只是控制内核回收匿名页相对于文件页的“倾向程度”。拿极端值举例swappiness0内核会尽量不回收匿名页。注意是“尽量”不是“绝不”。一旦内存压力非常大、文件页又回收不出足够空间时匿名页依然会被换出否则系统只能OOM杀进程。在部分内核版本上极端内存压力下如果死死压住匿名页回收反而可能出现直接回收反复扫描、CPU使用率异常升高的情况。swappiness100内核把匿名页和文件页放在同等优先级上考虑回收甚至在某些情况下更偏向换出匿名页。它不代表系统会立刻把所有内存倒进swap只代表当内存不够时内核认为换出冷匿名页和回收缓存都是合理选项。用生活化一点的方式理解内存是你的桌面swap是旁边的抽屉柜。文件页是已经看完可以随手丢进碎纸机的资料匿名页是你正在填写的表格。swappiness就是决定你“多勤快地把桌面上的草稿挪进抽屉”的旋钮。设成0并不代表你永远不会把草稿放进抽屉只代表你希望桌面实在堆不下了才动手设成100则代表你更倾向于保持桌面整洁哪怕代价是频繁开抽屉。2. 不同场景下该设置多少先给结论再讲逻辑2.1 数据库类负载低值优先但不是越低越好如果机器主要跑MySQL、PostgreSQL这类数据库我的建议通常是vm.swappiness10。数据库的buffer pool、shared buffers会把热数据尽量留在内存里这类进程的匿名内存一旦被换出一次随机读的延迟可能从微秒级恶化到毫秒级甚至更高对查询性能影响很大。所以我们要尽量让匿名页留在物理内存里让系统优先回收文件页来满足内存需求。但为什么不是0因为需要预留一点弹性。数据库进程在一段时间内可能会因为连接数增加、临时结果集变大而突然吃掉更多内存这时候如果没有可用swap内核别无选择只能在内存压力下去激进扫描匿名页极端情况下还会触发OOM Killer把数据库进程杀掉。相比偶尔牺牲一小部分冷匿名页直接挂掉数据库是更不能接受的结果。我自己的习惯是纯内存型组件比如开启了持久化的Redis集群节点可以设10到30有大量文件缓存的MySQL、PostgreSQL设10是比较均衡的选择只有明确知道这台机器绝不会发生内存突发增长应用对延迟极度敏感时才考虑设0并且一定要配好告警。2.2 容器与 K8s 环境宿主和 cgroup 要分开看很多K8s节点上部署着各种微服务但我不建议直接在宿主机上一刀切改成0因为容器场景还要看cgroup这一层。在cgroup v2环境下每个cgroup都有自己的memory.swappiness默认继承父级。即使你在宿主机把vm.swappiness设为10容器里的进程在触发自身memory cgroup的内存回收时用的可能是当前cgroup的memory.swappiness而不是宿主机全局值。如果宿主机是systemd管理可以针对某个service单独设置systemctl set-property my-service.service MemorySwapMax0注意MemorySwapMax是限制swap使用量和swappiness是两回事但两者经常配合使用。如果你的容器直接跑在cgroup v2路径下也可以查看和临时调整cat /sys/fs/cgroup/memory.swappiness echo 10 /sys/fs/cgroup/memory.swappiness这个修改在cgroup销毁后会失效生产上要落到容器运行时配置或systemd单元文件里。在K8s里想可靠地调整节点内核参数通常建议走节点级sysctl配置或专门的初始化DaemonSet而不是手工进容器里改。因为容器内改/proc/sys通常需要特权而且重启镜像就丢。2.3 桌面系统与压缩 swap反而可能调高服务器上我们忌讳频繁swap但在桌面系统里情况可能相反。不少桌面发行版默认用zram或zswap把“swap”压缩后放在内存里而不是写进磁盘。这样一来换出匿名页的代价比写到机械盘或普通SSD低得多内存紧张时早点把冷页压缩存放反而能腾出更多物理内存给热数据和应用缓存。在这种场景下把swappiness调高一些比如80到100是合理的。比如Fedora Workstation在zram方案下把默认swappiness调到了较高值这是有意的设计。反过来说在zram环境里还死守swappiness0相当于明明有廉价的“内存压缩换出”机制不用非要等到物理内存极满再去触发更激进的文件回收反而浪费了zram的设计优势。2.4 内存充裕的新服务器保留 swap 比调零更有意义不少新服务器内存很大比如256G、512G很多同学心想“反正内存够大swap也没用”直接关swap或者设0。我的观点是内存再大也要保留一点swap尤其云主机和虚拟机环境。保留少量swap不是为了日常用它而是给内核一个“紧急缓冲垫”。如果应用层出现内存泄漏或者某个Java进程的堆突然暴涨内核可以先换出冷页来度过高峰而不是立刻进入直接回收甚至OOM。其次很多系统的systemd-oomd、earlyoom之类的机制会监测内存压力它们也需要swap配合辅助决策。没有swap时内存水位一旦见底可用的兜底手段就会少一个。内存大的机器我一般会做两件事挂一个2G到4G的swap文件并把vm.swappiness控制在10到30。这样既不会让系统动不动就碰swap又在关键时刻留了一条退路。3. 实操落地查看、修改、持久化一条龙3.1 先摸清系统当前状态动手改之前先看看当前值和整体内存分布cat /proc/sys/vm/swappiness sysctl vm.swappiness再看一下当前swap设备和用量free -h swapon --show顺便确认系统处于cgroup v1还是v2后面配置容器时需要stat -fc %T /sys/fs/cgroup如果输出是tmpfs说明是cgroup v2如果输出是cgroup则是v1。cgroup v1系统对memory.swappiness的cgroup级配置支持有限主要依赖全局参数。3.2 临时调整与永久生效临时生效一条命令就搞定sysctl -w vm.swappiness10这个操作立即生效不用重启但重启后失效。想要永久生效写入sysctl配置目录echo vm.swappiness10 /etc/sysctl.d/99-swappiness.conf sysctl --system这里我推荐在/etc/sysctl.d/下单独建一个.conf文件而不是直接往/etc/sysctl.conf里塞。原因是独立文件可追溯、可维护以后要换值只改一个文件就行也不会和系统里其他配置冲突。sysctl --system会按顺序加载这个目录下的配置文件99前缀在多数发行版上能保证较晚生效优先级更高。有一点要提醒云服务器如果用镜像模板批量创建光在单机里写sysctl.conf还不够需要把配置做进模板或初始化脚本里否则下次扩容出来的新机器又会回到默认值。3.3 修改后确认生效改完之后别急着走验证一下sysctl vm.swappiness cat /proc/sys/vm/swappiness如果目标平台有systemd并且你针对某个service设置了swap相关限制可以看看实际状态systemctl show my-service.service | grep -i swap对于长期运行的服务器我更建议把vm.swappiness纳入配置管理工具Ansible、Puppet、SaltStack都可以用统一的方式去管理。这种参数改动本身不大但一旦几百台机器配置不一致排查问题时很容易被忽略。4. 如何验证参数真的起了作用4.1 关注 si/so 和 pswpin/pswpout而不是 swap 剩余量很多人改完参数就盯着free -h里的Swap used看发现它没降就以为参数没生效。这是不对的。vm.swappiness影响的是内存回收时的倾向已经换出到swap的数据只要没有新的内存压力不会只因为改了参数就大幅回收到内存。你应该看的是swap交换活动。用vmstat看siswap in和soswap outvmstat 1想观察累计值就看/proc/vmstatgrep -E pswpin|pswpout /proc/vmstat如果swappiness调低之后so和pswpout在相同内存压力下明显下降说明匿名页被换出变少了参数作用就体现出来了。另外可以看看匿名页和文件页的回收计数grep -E pgsteal_anon|pgsteal_file /proc/vmstat低swappiness通常意味着回收的页里文件页占比更高也就是说系统更多通过丢弃缓存来释放内存而不是把进程内存搬去swap。4.2 用真实负载做一次小规模验证生产环境不敢乱搞可以在测试环境模拟一次内存压力。思路是先读取一个大文件让page cache占掉一部分内存。记录当前的pswpin、pswpout、pgsteal_anon、pgsteal_file。用stress-ng分配大量内存观察内存压力下的回收行为。在swappiness60和swappiness10两种设置下各跑一轮比较swap相关计数。一个相对安全的做法# 先制造page cache dd if/dev/zero of/tmp/bigfile bs1M count4096 cat /tmp/bigfile /dev/null # 记录基线 cat /proc/vmstat | grep -E pswpin|pswpout|pgsteal_anon|pgsteal_file # 制造内存压力 stress-ng --vm 2 --vm-bytes 80% --timeout 30s注意stress-ng的参数要根据机器实际内存调整别直接把系统压死。测试环境建议在VM里做生产环境更推荐用真实业务流量观察慢速变化而不是主动制造极端压力。4.3 长期观察的手段短期压测只能看出即时反应我更习惯配合监控系统看长期曲线。比较实用的指标是swap used变化量、page cache命中率如果应用能统计、系统负载和磁盘IO的关联。如果磁盘是机械盘swap IO和磁盘utilization一起飙升时多半是swappiness偏高导致的匿名页换出过于频繁调低之后这类峰值通常会明显减少。有些同学会问swappiness改了之后需不需要重启应用。一般不需要因为这只是内核回收策略应用进程无感知。除非你的应用内部有类似JVM的GC日志记录了swap事件那也只是观察层面受影响进程本身不需要重启。5. 常见的坑和排查记录5.1 重启后配置丢失这是我见得最多的问题sysctl -w改完当时生效重启后发现自己回到60。原因就是没写进配置文件或者写的位置不对。有些云镜像里的/etc/sysctl.conf可能被云初始化脚本覆盖你写进去的内容运行后又被重置。解决办法是确认操作系统是否有cloud-init或类似配置管理组件把自定义配置放到/etc/sysctl.d/下高优先级文件并在云平台的初始化脚本里固定下来。改完一定要用sysctl --system重新加载别只重开一个shell去看那容易产生“改了没生效”的错觉。5.2 内存明明没满swap 却还在涨有一种情况经常让人困惑free -h显示可用内存还很多Swap used却在缓慢上涨。这不一定是swappiness设高了更多时候是某些进程主动调用madvise、mlock相关机制或者内存整理时触发了swap。另一个常见原因是内核在后台预测到未来可能有内存压力会提前把一些冷页换出到swap这个行为在部分内核版本里甚至和swappiness的关系没那么直接。遇到这种问题先按进程查swap占用for f in /proc/[0-9]*/status; do awk /Name|VmSwap/{printf %s , $2} END{print } $f; done | sort -k2 -n -r | head -20找出谁在占用swap再针对那个进程去分析原因。如果是个长期不访问的守护进程它占swap本身不算什么大问题如果是数据库进程在占swap那就要检查内存分配策略和连接池设定了。5.3 容器内改 swappiness 不生效在容器里执行sysctl -w vm.swappiness10有时候会提示Permission denied有时候看起来成功了但实际上没作用。原因是容器共享宿主机内核这个参数在/proc/sys/vm/下面属于全局参数普通容器没有权限改即使有权限改了也会影响整个宿主机而不是只影响当前容器。正确做法分两层有特权时在宿主机层调整全局参数cgroup v2环境下用memory.swappiness对特定cgroup做限制再配合K8s Node级别的sysctl配置做统一管理。总之别指望在容器内部一条命令解决所有问题。5.4 调了参数还是频繁 swap先看内存分配方式如果swappiness已经设到10甚至5swap使用还在上升这时候不能只盯着参数要去看进程的内存分配习惯。很多服务端程序存在内存碎片问题或者用了过多的匿名映射还有的GC类语言在高峰时会突然向内核申请一大块内存这些都会造成瞬时swap写入。还有一种情况是内存总量确实不匹配负载比如4G内存跑Java应用堆就给了3G那swappiness设成再低也没办法物理内存已经见底内核必须换页来腾空间。这种情况下我的建议顺序是先优化应用内存占用和堆配置再看是否需要扩容内存最后才考虑微调swappiness。参数只是最后一道调节阀不能替代容量规划。5.5 顺带提一个容易搞混的参数vm.vfs_cache_pressure调swappiness的时候经常有人把vm.vfs_cache_pressure一起改这个参数控制目录项和inode缓存回收的倾向。数值越高内核越积极回收文件系统元数据缓存默认100调低到50可以让这类缓存更持久。它和swappiness并不是一回事但两者会共同影响内存回收的整体行为。如果你在做内存调优建议把swappiness、vfs_cache_pressure、page cache相关策略放在一起看别只改一个就下结论。我踩过的一个坑是把vfs_cache_pressure直接调到0结果某些场景下目录项缓存长期占用大量内存导致其他进程可用内存反而变少。后来我把它控制在50到100之间效果比极端值好得多算是“过度调优”的典型反面教材。写到最后简单说一点我的个人体会。vm.swappiness没有一劳永逸的标准答案网上流传的“一律设0”和“设100”都过于极端。合理的做法是先想清楚你的负载模型内存里是热数据重要还是快速响应文件读更重要是宁可轻微交换保命还是宁可让进程常驻内存绝不换出。然后把测试环境当试验场结合监控数据去找那个平衡点。我目前最常用的组合是普通Web服务10到30数据库10左右桌面或zram环境80到100内存极大且负载很平稳的机器才考虑0并配好告警。如果哪天你在生产环境改了参数之后反而出现莫名卡顿不要犹豫先回滚配置再从内存分配和应用行为的角度去查。参数是死的系统是活的把原理吃透比记住某个推荐值有用得多。

相关推荐

基于IEEE 14节点的电力系统碳排放流计算与Matlab实现
基于IEEE 14节点的电力系统碳排放流计算与Matlab实现

做电力系统方向的研究,尤其是涉及“双碳”和低碳转型的课题,绕不开一个很实际的问题:电网把电能从发电侧送到用户侧,中间那一段段错综复杂的潮流里,产生的碳排放到底该怎么划分?如果只按发电量乘以排放因子… · 2026/9/24 22:00:23

为什么哺乳动物没有绿色毛发?色素、结构色与进化的答案
为什么哺乳动物没有绿色毛发?色素、结构色与进化的答案

开头去年冬天带着侄子去逛自然博物馆,他在两爬展柜前蹲了老半天,突然回头问了我一句:“叔叔,为什么有绿色的蜥蜴、绿色的鸟,就是从来没有绿色的猫和狗?”我当时被问得愣了一下。仔细想想,好像真… · 2026/9/24 22:00:23

MyBatis-Plus实体类字段忽略:@TableField(exist=false)用法与避坑指南
MyBatis-Plus实体类字段忽略:@TableField(exist=false)用法与避坑指南

作为一个整天和 MyBatis-Plus 打交道的后端开发,我第一次遇到实体类加字段导致 SQL 报错,是在一个周四下午。当时订单列表接口突然全部 500,日志里冒出一句SQLSyntaxErrorException: Unknown column role_names in field list。我第一反应是数… · 2026/9/24 22:00:23

Java实现双向堆叠LSTM电力负荷预测:DL4J实战与避坑指南
Java实现双向堆叠LSTM电力负荷预测:DL4J实战与避坑指南

简介:这是一份基于双向堆叠LSTM的电力负荷预测系统Java完整项目,专为计算机相关专业学生、毕业设计及课程设计人群打造,可用于毕业论文实现与负荷预测算法入门。系统采用堆叠式双向LSTM构建预测模型,配套JavaFX图形界面展示预测结… · 2026/9/24 22:36:03

网络热词cua全面解析:从电竞圈到社交暗号的传播密码
网络热词cua全面解析:从电竞圈到社交暗号的传播密码

最近刷社交平台,总能看到“cua”这个词在评论区、弹幕、甚至朋友聊天里冒出来。一开始我以为只是某个主播的口癖,后来发现不对劲——数量太多、用法太杂,已经有点“万物皆可cua”的味道了。作为一个常年泡在互联网各种圈层里的观察者&#xf… · 2026/9/24 22:36:03

ONVIF SDK封装实战:从WSDL生成到IPC接入避坑指南
ONVIF SDK封装实战:从WSDL生成到IPC接入避坑指南

简介:这是一个面向Java开发者的Onvif协议封装SDK,基于Spring Boot与SOAP通信实现,适合需要快速对接网络摄像头、构建视频监控系统的工程师。压缩包共48个文件,主要包括3个Java源码(含TestController.java调用示例&… · 2026/9/24 22:36:03

基于西门子S7-200的散料自动配料装车系统设计与实践
基于西门子S7-200的散料自动配料装车系统设计与实践

1. 项目整体设计与系统架构1.1 核心需求解析:这套系统到底解决什么问题先聊点实在的。只要你在粉料、骨料、化工粒子这一类散装物料行业待过,就一定见过那种最原始的装车方式:一个料仓,一根落料管,一个工人站在车顶上&… · 2026/9/24 22:36:03

GPU 在等数据,具身模型训练中常被忽视的 DataLoader
GPU 在等数据,具身模型训练中常被忽视的 DataLoader

无论训练大语言模型还是具身模型,GPU 侧的计算与通信都是首先需要优化的环节。但对以视频为主要训练数据的 VLA 和 WAM 来说,仅仅优化 GPU 还不够。它们的训练样本难以全部提前处理并存储,所需视频帧往往要在训练过程中按需读取、在线解码。数… · 2026/9/24 22:36:03

S7-200 PLC自动配料装车系统实战:从称重选型到落差补偿
S7-200 PLC自动配料装车系统实战:从称重选型到落差补偿

忘了是哪个现场了,反正那几年手里过的配料的活儿不少。接到“西门子S7-200自动化配料装车系统”这种单子,第一反应不是看程序怎么写,而是得先想明白:水、砂石、水泥、粉煤灰、外加剂,或者化工里的几种粉料、颗粒料&… · 2026/9/24 22:35:57

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程
基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为… · 2026/9/24 0:00:13

1D-CNN时间序列建模实战:从Conv1d原理到工业落地
1D-CNN时间序列建模实战:从Conv1d原理到工业落地

简介:面向时间序列数据建模的一维卷积神经网络完整实现,适合深度学习入门者及需要快速验证时序模型的研究者,能够从音频、文本、传感器或股价等序列中挖掘局部特征与时间依赖。压缩包体积很小,只有3KB,内含3个Python脚… · 2026/9/24 0:00:26

柔软的L:汉语语流中被忽视的舌肌张力控制
柔软的L:汉语语流中被忽视的舌肌张力控制

1. 这个“L”不是字母表里的L,而是舌尖上的L最近在几个方言群和语音教学社群里,反复看到有人发一句:“也说字母L:柔软的长舌”。初看以为是英语发音课笔记,点开才发现全是方言爱好者、播音系学生、语言康复师甚至戏曲演… · 2026/9/24 0:00:44

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码