news 2026/10/7 1:59:28

银河麒麟V10内存不释放?MemAvailable与定时清理实战解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
银河麒麟V10内存不释放?MemAvailable与定时清理实战解析

简介:面向银河麒麟V10服务器运维人员的内存泄漏排查与定时清理方案,解决系统长时间运行后可用内存逐渐减少、性能下降甚至宕机的隐患。压缩包共3个文件,含2个shell脚本与1个txt配置说明,脚本用于定时监控并释放内存,txt文档阐述配置参数与部署注意事项,整体仅2KB,轻量易部署。已有773人学习下载。资料围绕内存监控、自动清理、日志分析与系统参数调优展开,可直接参考脚本逻辑融入现有运维流程,也可结合Valgrind等工具进一步排查泄漏源头,并配合top、free等命令验证效果,适合负责国产化服务器日常巡检与性能优化的运维工程师快速上手。

1. 银河麒麟V10“内存不释放”不是玄学:定时清理前先分清缓存和泄漏

在国产化替换项目里,银河麒麟V10服务器版(Kylin Linux Advanced Server V10,内核Linux 4.19系列)跑上业务系统后,运维最常收到的告警就是“内存不释放”:free里used冲到90%以上,客户指着监控截图要说法。可多数情况下,那并不是内存泄漏,而是Linux把空闲内存拿来做了文件缓存,这部分内存在业务需要时能随时交回去。本篇文章要解决的是:在银河麒麟V10上判断内存是真不够还是“假不释放”,再通过 cron 定时触发一个带条件的释放脚本,把可用内存水位控制在合理范围内,同时不伤业务缓存、不引发磁盘IO雪崩。适合实施运维、虚拟化交付和接手国产化服务器的一线工程师。

2. 判断内存到底够不够:用 MemAvailable 把“假高”和“真缺”分开

2.1 free 和 /proc/meminfo:看得懂的才是能回收的

很多人在银河麒麟V10上执行free -h,只盯着used那一列看,这是后续所有误判的起点。Linux 的free输出里,used是“已经被分配出去”的内存,包括进程占用和内核缓存;而available才是“在不触发换页、不OOM的前提下,还能分配给新进程的真实余量”。两者的差值,主要来自buff/cache里可回收的部分。银河麒麟V10的内核是4.19系列,MemAvailable这个统计项是完整可用的,所以判断内存是否紧张,第一件事就是执行下面的命令:

grep -E "MemTotal|MemFree|MemAvailable|Cached|SReclaimable|Shmem|Dirty" /proc/meminfo

重点看三个值:MemTotal是物理内存总量;MemAvailable是应用真正可用的余量;Cached加SReclaimable是内核里可以被回收的缓存和slab对象。写脚本时,我用的是MemAvailable / MemTotal的百分比,而不是MemFree,因为MemFree在内存充足的机器上往往低得吓人,但它不反映可回收缓存。换句话说,只要MemAvailable占比健康,used高位运行是正常现象,不是故障。

对应关系可以按这张表来理解:

/proc/meminfo 字段free 命令中的位置含义能否回收
MemTotaltotal物理内存总量-
MemFreefree完全空闲的物理页-
MemAvailableavailable新进程可用的估算余量-
Cachedbuff/cache文件缓存页可回收
SReclaimablebuff/cache可回收的内核slab对象可回收
Shmembuff/cache共享内存(tmpfs等)不可简单回收

Shmem是容易忽略的坑:它显示在buff/cache里,却不能被drop_caches回收。清理脚本如果只盯着cache总量,会误以为清理不彻底。

2.2 伪不释放和真不释放:什么情况下清理脚本救不了你

我把线上遇到的情况分成两类。第一类是“伪不释放”:MemAvailable占总内存的百分比在正常水位,used虽高,但容器、Java进程、数据库一申请内存,内核立刻压缩缓存让出页面,业务毫无感知。这种情况根本不需要定时清理,硬清反而会把磁盘读缓存打掉,拖慢IO。

第二类是“真不释放”,特征更明显:MemAvailable长期低于总内存的10%甚至5%,Dirty页持续增长,swap 分区开始产生实际使用量,MySQL、Elasticsearch 等进程的 RSS 只升不降,业务出现卡顿或连接超时。这种情况要区分两个层次:如果是进程自己的堆和RSS在增长,drop_caches一点忙都帮不上,那是代码或JVM参数的问题;如果是内核slab、dentry/inode 缓存异常膨胀,才轮到清理脚本上场。

判断命令可以这么用:

ps aux --sort=-%mem | head -n 8 cat /proc/slabinfo | awk 'NR>2 {sum+=$2} END {print "slab_used_kb:", sum}'

ps负责定位哪个业务进程在持续吃内存,slabinfo负责看内核可回收对象占了多少。如果 slab 总量不大、进程RSS又居高不下,那接下来的定时清理脚本对这个场景是无解的,应该去查应用的连接池、GC参数、或者是否在循环加载大文件。我通常只对“伪不释放但客户不认可”和“slab/cache 异常膨胀”这两种情况做定时释放。

3. 用 cron 做定时释放:最小清理脚本与两种调度方式

3.1 写一个带阈值判断的内存清理脚本

定时清理的第一步,是把“释放内存”做成一个带条件的动作,而不是一句无脑的echo 3 > /proc/sys/vm/drop_caches。原因后面第5章会展开,这里先给脚本。我的做法是把清理脚本放到/usr/local/sbin/clean_mem.sh,内容如下:

#!/bin/bash # 银河麒麟V10内存回收脚本:只在可用内存低于阈值时清理缓存 # 适用场景:page cache 占用高、MemAvailable 持续偏低、无内存泄漏进程 MEM_TOTAL=$(awk '/MemTotal/{print $2}' /proc/meminfo) MEM_AVAILABLE=$(awk '/MemAvailable/{print $2}' /proc/meminfo) AVAIL_RATIO=$(( MEM_AVAILABLE * 100 / MEM_TOTAL )) # 结合绝对值和比例,避免大内存机器长期不触发 MIN_AVAILABLE_KB=$(( 10 * 1024 * 1024 )) logger -t clean_mem "check memory: available=${MEM_AVAILABLE}KB ratio=${AVAIL_RATIO}%" if [ "$MEM_AVAILABLE" -lt "$MIN_AVAILABLE_KB" ] || [ "$AVAIL_RATIO" -lt 10 ]; then sync echo 1 > /proc/sys/vm/drop_caches logger -t clean_mem "drop_caches=1 executed, ratio was ${AVAIL_RATIO}%" fi

这个脚本做了三件事:读取MemTotal和MemAvailable,按百分比和绝对值双重判断,最后只写echo 1而不是echo 3。echo 1只释放文件缓存页,echo 3会连 dentry 和 inode 缓存一起清空——对绝大多数业务系统,echo 1已经足够,清 dentry 反而会在高并发文件访问场景造成瞬时iowait飙升。同步执行sync是为了先把脏页落盘,避免数据丢失风险。

参数说明:阈值我一般设在MemAvailable < 10%或< 10GB时触发,两个条件任一满足即可。这是为了照顾超大内存机器——512GB物理内存的机器,10%也有51GB,看起来很多,但某些数据库或虚拟化平台在高峰期的临时分配远大于这个数;而如果只看绝对值,96GB的小机器又可能永远达不到10GB的下限。logger会把每次检查记录到系统日志,排错时不用猜脚本到底跑没跑。

3.2 注册定时任务:crontab 和 systemd timer 两种做法

脚本就位后,给执行权限并做一次手动验证:

chmod +x /usr/local/sbin/clean_mem.sh /usr/local/sbin/clean_mem.sh grep clean_mem /var/log/messages

确认日志里有check memory输出后,再注册定时任务。银河麒麟V10服务器版自带crond,最省事的方式是直接写crontab:

crontab -e

内容加入下面一行(注意 cron.d 方式时必须写用户字段):

*/30 * * * * /usr/local/sbin/clean_mem.sh >/dev/null 2>&1

每30分钟检查一次,绝大多数业务够用。频率太低会让可用内存长期处于低位,太高则会让drop_caches频繁执行,反而降低缓存命中率。我在实际项目里会按业务窗口调整:白天30分钟一次,凌晨批处理期间改成10分钟一次,但不会低于这个值。

更推荐的一种做法是使用 systemd timer,尤其当机器上 SELinux 开启、cron 脚本执行权限出现诡异问题的时候。systemd timer 有两个文件。先建 service:

cat > /etc/systemd/system/clean-mem.service << 'EOF' [Unit] Description=Clean kernel cache on Kylin V10 when memory low [Service] Type=oneshot ExecStart=/usr/local/sbin/clean_mem.sh EOF

再建 timer:

cat > /etc/systemd/system/clean-mem.timer << 'EOF' [Unit] Description=Run clean-mem every 30 minutes [Timer] OnCalendar=*:0/30 Persistent=true [Install] WantedBy=timers.target EOF

然后启用并验证:

systemctl daemon-reload systemctl enable --now clean-mem.timer systemctl list-timers clean-mem.timer

OnCalendar=*:0/30表示每半小时触发一次,Persistent=true让机器在休眠或关机补跑错过的任务。相比 crontab,systemd timer 的日志直接进 journald,排查“任务到底跑没跑”时一条journalctl -u clean-mem就能看完,不需要再翻/var/log/cron。我个人的习惯是优先用 systemd timer,尤其在银河麒麟服务器版上,省去不少PATH和SELinux带来的血泪问题。

4. 让清理更温和:调整 vfs_cache_pressure 和内存水位参数

4.1 四个内核参数:清什么、多久清一次才不伤缓存

定时脚本解决的是“内存不够时腾空间”,但如果内核本身就抗拒回收,或者回收时触发大量IO,脚本效果会很差。在银河麒麟V10上,我一般会同时调四个参数,按业务场景组合使用。

先用一条命令查看当前值:

sysctl vm.vfs_cache_pressure vm.min_free_kbytes vm.dirty_background_ratio vm.dirty_ratio

最常用的是vm.vfs_cache_pressure,默认100。这个值控制内核回收 dentry/inode 缓存的倾向:数值越大越激进,文件访问越频繁的系统调低到50左右可以让元数据缓存更持久;相反,如果内存压力大并且文件数量特别多,可以调高到200。很多文章建议直接改成10,我不建议照抄——vfs_cache_pressure 过低会让大量文件名和目录结构长期赖在内存里,对跑NFS、对象存储网关注册中心的机器,Metadata 缓存会占到几个GB,而且要等内存压力极高才回吐。

vm.min_free_kbytes是给关键内存分配保留的底线,默认值往往偏低。512GB内存的机器建议设到 4GB 或更高,避免在内存水位很低时,内核为了凑页面频繁做直接回收导致卡顿。命令如下:

sysctl -w vm.min_free_kbytes=4194304 sysctl -w vm.vfs_cache_pressure=100 sysctl -w vm.dirty_background_ratio=5 sysctl -w vm.dirty_ratio=20

需要持久化写入/etc/sysctl.d/99-memory-tuning.conf,因为sysctl -w在重启后失效。银河麒麟V10的 sysctl 配置目录是完整的,新建文件即可。参数对照如下:

参数默认值调整方向适用场景
vm.vfs_cache_pressure100调高到150-300文件数量大、内存压力高、定时清理频繁
vm.vfs_cache_pressure100调低到50-80频繁访问小文件、缓存命中率更重要
vm.min_free_kbytes视内存而定总内存的0.5%-1%数据库和虚拟化宿主机
vm.dirty_background_ratio10调低到5IO能力弱、怕突发落盘
vm.dirty_ratio20调低到10-15业务写放大明显、需要限制脏页堆积

注意/proc/sys/vm/drop_caches每次写完后内核会自动重置为0,不存在“一直在清”的状态。它让内核唤醒内存回收工作来释放可回收页,而不是把已分配给进程的内存强行收回。所以定时脚本做得再频繁,也影响不到业务进程自身占用的RSS。

4.2 进程级限制:定时清理治不了的顽固内存怎么办

上一节确认了,如果“真不释放”来自业务进程本身,脚本只能腾出缓存,救不了进程。这时我必须把手段切换到进程级限制。银河麒麟V10支持cgroup,systemd 自带资源控制,可以用systemd-run把某个进程装进资源限制的scope里,例如限制单个服务最大内存:

systemd-run --scope -p MemoryMax=4G -p MemorySwapMax=1G --unit=limit-mem /usr/bin/myapp

这个命令会启动一个临时scope,MemoryMax后面是硬上限,超过就触发OOM killer;MemorySwapMax限制该进程能用的swap量,防止进程把swap吃满拖死宿主机。接线到生产时,我会先观察业务峰值内存,设置成峰值的120%,避免误杀。cgroup version 1 环境对应的是memory.limit_in_bytes和memory.swappiness,银河麒麟V10服务器版默认挂载哪种取决于内核启动参数,不要想当然,先执行mount | grep cgroup确认。

这类限制的副作用也必须讲清楚:MemoryMax设得太低会导致进程被OOM kill,MySQL、Java这类会预留大量堆内存的应用尤其危险。更好的做法是先设MemoryHigh或调高vm.swappiness到30,让内核在接近上限时优先回收匿名页和文件缓存,而不是直接杀进程。把“定时清理”和“进程限制”组合使用时,顺序应该是:脚本负责兜底回收缓存,cgroup 负责限制失控进程,两者不要互相替代。

5. 银河麒麟V10 定时清内存的常见问题与排查

5.1 定时任务没跑起来:脚本权限、PATH 与 SELinux 是重灾区

现象:手动执行/usr/local/sbin/clean_mem.sh完全正常,日志也打出check memory,但定时任务就是没有执行记录。

原因:第一是 cron 的 PATH 环境非常精简,脚本内如果用到/usr/local/bin下的命令,就会静默失败;第二是银河麒麟默认开启 SELinux,/usr/local/sbin下的脚本如果安全上下文不对,会被阻止执行;第三是 cron.d 文件格式错误。解决时我会先运行crontab -l和tail -n 50 /var/log/cron确认调度记录,然后检查/usr/sbin/getenforce。如果是 Enforcing,临时跑一遍restorecon -v /usr/local/sbin/clean_mem.sh重打安全上下文即可。最省心的根治方案是改走 systemd timer,避开 cron 和 SELinux 的交互问题。

5.2 业务高峰清缓存:释放了内存,也放大了磁盘 IO

现象:定时任务白天跑了之后,free 里 available 确实上升,但紧接着业务系统反映变慢,top里iowait飙升,数据库查询耗时翻倍。

原因:清理脚本把从磁盘读过的热点数据页全丢弃了,数据库和文件服务只能重新从存储把数据加载回内存,IO压力瞬时拉满。drop_caches只负责“腾地方”,不负责“不疼”。解决时我把脚本执行时段限制在低峰期,比如在 cron 表达式里只让凌晨1点到5点执行,并加上时间判断,白天只记录指标不清理:

HOUR=$(date +%H) if [ "$HOUR" -ge 1 ] && [ "$HOUR" -le 5 ]; then sync echo 1 > /proc/sys/vm/drop_caches fi

同样,清理前多看一眼vm.dirty_ratio,脏页多的时候sync本身就会造成一次大的落盘。平时把第4章里的dirty_background_ratio调低,让脏页持续落盘,清理时就不会出现尖刺。

5.3 虚拟机和超大内存机器:别用同一个比例阈值

现象:同一套百分比阈值,在256GB物理机上几乎不触发,在16GB小虚拟机上一小时触发八次,业务缓存形同虚设。

原因:比例法在超大内存下失真。256GB的10%是25.6GB,足够大多数进程临时分配;而16GB的10%只有1.6GB,随便跑个Java应用就触底。解决时我用“百分比 + 绝对值”双条件,绝对值下限设为min(10GB, 10%物理内存),这是我在第2章脚本里保留MIN_AVAILABLE_KB的原因。上线前先用监控确认业务水位,再去调脚本里的数值,不要照搬我这组参数。

5.4 明明 cache 清了,free 的 used 还是高

现象:执行echo 1 > /proc/sys/vm/drop_caches后,free -h第一行used几乎没变,客户质疑“清理脚本是不是假的”。

原因:used包含进程RSS、内核slab、不可回收的Shmem等所有已分配页。drop_caches只回收文件缓存和部分可回收slab,在大量进程活跃的机器上,这些进程自身的内存占用比缓存大得多。解决时我强调看MemAvailable而不是used,并在交付报告里把available作为唯一验收指标。如果客户坚持要看used下降,那大概率是进程层的真占用,该走 cgroup 限制或优化业务配置,而不是继续加急清理脚本。

5.5 清理后内存很快又涨回高位,日志里全是执行记录

现象:脚本每30分钟跑一次,日志证明每次都在清理,但MemAvailable还是持续偏低,业务继续告警。

原因:说明系统有真实的频繁内存分配需求,比如连接池膨胀、临时文件缓存、内核模块的slab增长,你的缓存刚腾出来又被同一批业务逻辑占用。定时清理变成了给一个漏水桶舀水。解决时我停止无脑清理,转做两项定位:ps aux --sort=-%mem找RSS大户,cat /proc/slabinfo | grep -E "kmalloc|radix_tree_node|dentry"找内核对象增长。如果是Java应用,调-Xmx和GC参数;如果是文件缓存层,用vfs_cache_pressure调节收益更大,而不是靠清理脚本硬扛。

6. 把内存释放变成可观测的日常:一分钟验证与配置习惯

定时任务上线不等于事情结束,我会把“是否该清理、清理有没有效”变成一条可观测的日常检查。每次脚本执行后,在/var/log/messages里用logger留下的记录只是第一步,更完整的是把清理前后的指标追加到自定义日志,留作后续排查的数据:

AVAIL_BEFORE=$(awk '/MemAvailable/{print $2}' /proc/meminfo) sync echo 1 > /proc/sys/vm/drop_caches sleep 1 AVAIL_AFTER=$(awk '/MemAvailable/{print $2}' /proc/meminfo) echo "$(date '+%F %T') before=${AVAIL_BEFORE}KB after=${AVAIL_AFTER}KB" >> /var/log/clean_mem_release.log

验证时我会跑一次free -w -h确认 available 变化,看一下iowait是否在随后一分钟内回落。这里有一个容易忽略的习惯:清理后立刻看iowait如果是 100%,说明刚才把热点缓存打没了,业务在重新加载数据,这时候要回退脚本阈值,而不是加大清理频率。

我还习惯把阈值、清理级别、最低可用内存这些值抽到配置文件/etc/clean_mem.conf,让脚本去读,而不是直接裸改代码。这样接手的同事不用打开 Bash 脚本就能看懂策略,也不会出现一个人把echo 1改成echo 3、另一个人在另一台机器上踩坑的情况。配置项就三个:min_available_ratio、min_available_kb、drop_level,脚本里source /etc/clean_mem.conf加载,每次只动这一处。

最后还想说一个我自己的教训:线上遇到内存告警,先做判断再做动作,先让监控说话再让脚本干活。定时清理是手段,保证 MemAvailable 健康才是目的,顺序反了会越清越忙。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/7 1:55:29

VSCode本地AI插件卡顿根源:协议税与UDS通信优化实战

1. 问题不是“卡”&#xff0c;是通信链路在 silently 拖垮响应——从 Roo Code 的真实日志说起Roo Code 这个插件&#xff0c;最近在 VSCode 社区里讨论热度很高。它主打“本地模型直连”&#xff0c;宣称能绕过云端 API&#xff0c;把 Llama、Gemma、Phi 等模型直接塞进编辑器…

作者头像 李华
网站建设 2026/10/7 1:54:42

AI Agent七要素:从架构图到故障排查地图的工程落地指南

1. 为什么“七要素”不是设计清单&#xff0c;而是故障排查地图我第一次在团队里讲 AI Agent 架构时&#xff0c;画了张漂亮的七要素图&#xff1a;Memory、Planning、Action、Observation、Tool Use、Reasoning、Self-Correction——每个框都配了图标&#xff0c;还标了箭头循…

作者头像 李华
网站建设 2026/10/7 1:54:39

MinerU 4.0 Windows本地部署实战指南

1. 为什么非得在 Windows 上本地跑 MinerU 4.0&#xff1f;——直击 RAG 预处理的三个真实断点你是不是也经历过这样的场景&#xff1a;用现成的 RAG 工具链跑 PDF&#xff0c;结果一打开就报错“PDF contains encrypted content”&#xff1b;或者上传一份带复杂表格和公式的工…

作者头像 李华
网站建设 2026/10/7 1:54:22

Python调用百度云API实现微博评论情感分析实战

简介&#xff1a;这份资源面向希望入门文本情感分析与API调用的Python学习者&#xff0c;围绕微博评论情感偏向判断这一课题展开。包内提供可供参考的微博评论数据集&#xff0c;以及调用百度云API获取文字情感得分、再对得分进行标准化处理以得到实际倾向的脚本&#xff0c;帮…

作者头像 李华