银河麒麟V10内存缓存清理与定时任务实战

发布时间:2026/9/8 14:25:42
银河麒麟V10内存缓存清理与定时任务实战 简介银河麒麟V10作为国产服务器操作系统内存不释放会逐步吞噬可用内存导致性能下降甚至宕机。该资源面向运维工程师针对上述痛点提供了一套定时治理方案基于系统自带命令与定时机制无需额外复杂依赖。压缩包共3个文件包含2个Shell脚本和1个配置说明文本整体仅2KB轻量易用。两个脚本分别负责内存状态检测与定时执行逻辑配置说明则阐述了脚本参数含义、部署方式及注意事项可直接集成进crontab实现自动化运维。已有749人学习下载适合需要长期维护国产化服务器、希望减少手动干预的技术人员参考。借助这套小工具运维人员能够快速定位内存占用异常定期执行缓存释放与进程整理从而提升银河麒麟V10系统的稳定性与资源利用率。 前阵子公司一台银河麒麟V10服务器又出现了老问题跑了两周多free看到可用内存只剩两三百MBswap被狂吃连ssh登录都卡顿。当时第一反应是某个服务炸了结果top一看进程占用加起来不到4GB大头全在cached。更尴尬的是跟同事聊起这事发现不少人把“内存不释放”等同于“内存泄漏”上来就重启机器或者干脆写个死循环定时清理。思路没错但工具和姿势很重要尤其是银河麒麟V10这种基于Linux内核又带国产化软件栈的系统处理起来比标准CentOS要更谨慎。这篇文章我想完整记录一下我怎么定位这个问题、怎么设计定时清理脚本、以及怎么挂到定时任务里。文章主要适合两类人一是使用银河麒麟V10服务器版/桌面版的运维和开发二是对Linux内存回收机制感兴趣、想搞清楚“缓存为什么越占越多”的朋友。我会把能直接抄作业的命令和脚本都放出来也会说清楚每个步骤背后的逻辑。1. 先搞清楚“不释放”到底是不释放什么1.1 你看到的内存数据应该怎么读先说结论手动清理的不是应用进程的RSS内存而是Linux内核的page cache页缓存。在很多Linux教程里都有这么一句话——free看到used很高不一定是坏事因为Linux会尽量用空闲内存来缓存文件、目录项、inode等。银河麒麟V10也一样它继承的是长期维护的内核分支页面回收机制、kswapd行为、cache水位线处理方式都和主流发行版类似。具体看上图的感觉是这样free -h输出类似total used free shared buff/cache available Mem: 15Gi 4.1Gi 286Mi 180Mi 10Gi 10Gi很多人一看used 4.1G、free只有286M就慌了。实际上available显示的是10G说明系统认为还有10G可用内存。这个available才代表应用可以实际使用的内存它是把可回收的cache算进去的。在银河麒麟V10上我建议养成看两列的习惯free的第三列和最后一列。第一列是彻彻底底没被占用的物理内存平时低一点很正常最后一列是系统估算的真实可用内存。如果available也在掉才需要紧张。1.2 麒麟V10上最容易发生内存异常的两个场景我排查过好几台麒麟V10发现内存异常主要集中在这两类场景里。第一类是桌面版。银河麒麟V10桌面版默认带UKUI桌面环境还挂了一批自启组件、窗口管理器、系统监控采集服务这些进程虽然单个占用不高但数量多、长日志多跑久了容易出现Slab内存、文件缓存越积越多的情况。配合WPS、浏览器这种重内存应用物理内存很快就见底。第二类是服务器版跑数据库或Java服务。比如有同事在麒麟V10上部署过PostgreSQL和Tomcat这些应用本身占用大再加上系统缓存内存就非常紧张。之前我遇到过一台服务器Java堆明明只配了4G但full GC频繁原因不是堆不够而是机器整体内存被缓存吃满内核频繁回收、swap开始大量写入整个进程反而变慢。所以“内存不释放”很多时候要分两层看进程内存是否持续增长以及系统缓存水位是否异常偏高。前者是程序问题后者才是“清理脚本”能解决的部分。2. 定位内存大户进程泄漏还是缓存堆积2.1 二十秒摸清内存现状拿到一台卡到不行的麒麟V10我先跑这几条命令free -h ps aux --sort-%mem | head -15 cat /proc/meminfo | grep -E MemTotal|MemAvailable|Cached|Buffers|SReclaimable|SwapTotal|SwapFreefree看全局ps看进程排序cat meminfo看内存细项。我最关注的是Cached、SReclaimable可回收的slab和SwapFree。如果Cached占了总内存的60%以上、SwapFree又很少基本就是缓存堆积系统开始用交换分区的状态。如果ps里某个进程的内存RSS高得离谱而且重启这个进程后内存马上回落这才算真正的进程级内存泄漏。如果ps加起来数值不大内存却不够用那几乎可以断定是内核缓存和页表吃掉了空间。2.2 从进程列表到实时采样光看静态的ps还不够我会用pidstat做一次采样确认不是瞬时波动pidstat -r 5 5这个命令每5秒采样一次连续5次能看到每个进程的实际内存增长趋势。如果某个Java进程或数据库进程的RSS从2G一路涨到4G、再到6G那就是它自身在积累对象、连接或日志缓冲区光清系统缓存解决不了问题。我还习惯看进程级别的详细内存cat /proc/$(pidof java | awk {print $1})/status | grep -E VmRSS|VmSwapVmRSS是物理内存占用VmSwap是这进程有多少内存被换到swap去了。如果VmSwap很高说明系统曾经物理内存不足把它挤出到交换分区了。2.3 特殊情况桌面版和数据库服务桌面版的场景稍微不一样。麒麟V10桌面版有时会遇到窗口管理器或系统托盘组件内存持续增长。我不建议在桌面环境上做太激进的cache清理因为用户感知最明显的是界面卡顿而频繁清cache会导致打开应用时全部重新读盘看起来更卡。对于跑PostgreSQL、MySQL这类数据库服务的服务器我还要额外看shared_buffers和连接数。一般情况下数据库的shared_buffers设置得过高加上系统缓存内存就非常紧张了。遇到这种情况建议先把数据库配置里的内存参数降下来而不是纠结系统缓存为什么不清。3. 定时清理脚本设计把简单活干高级3.1 清理内核缓存的正解Linux内核提供了一个接口允许主动回收缓存sync echo 1 /proc/sys/vm/drop_cachesecho 1释放page cache页缓存echo 2释放目录项和inodeecho 3释放page cache、目录项和inode实际操作中大部分人直接写echo 3 /proc/sys/vm/drop_caches因为简单。但我建议加一道保险先执行sync把内存里的脏数据写回磁盘否则有可能导致未落盘的数据丢失。虽然现代内核有日志系统和回写机制兜底但专业的运维习惯还是先sync再清。另外这个接口每次写入后会自动重置为0不用手动恢复。同时它需要root权限普通用户没有写/proc/sys/vm/drop_caches的权限。3.2 一套带阈值判断的脚本我最开始也是写死定时清cache后来发现有个麻烦每次清完cache应用第一次访问数据就会全部从磁盘重新读数据库的裸IO压力瞬间增大偶尔还会把业务请求堵住。所以我把脚本改成“内存使用率超过阈值才清理”平时不干预。下面是我跑了很久的脚本放在/usr/local/sbin/clean_mem_cache.sh#!/bin/bash # 银河麒麟V10 内存清理脚本 # 当内存使用率超过阈值时清理内核缓存 MEM_THRESHOLD80 LOG_FILE/var/log/mem_clean.log # 计算当前内存使用率这里是used/(total)的原始比例不计算available MEM_TOTAL$(awk /^MemTotal:/{print $2} /proc/meminfo) MEM_AVAILABLE$(awk /^MemAvailable:/{print $2} /proc/meminfo) MEM_USED$(( (MEM_TOTAL - MEM_AVAILABLE) * 100 / MEM_TOTAL )) echo $(date %Y-%m-%d %H:%M:%S) 当前内存使用率: ${MEM_USED}% $LOG_FILE if [ $MEM_USED -ge $MEM_THRESHOLD ]; then # 先同步磁盘再清理缓存 sync echo 3 /proc/sys/vm/drop_caches echo $(date %Y-%m-%d %H:%M:%S) 内存使用率超过阈值已执行缓存清理 $LOG_FILE # 清理后再验证一次 sleep 2 MEM_AVAILABLE_NEW$(awk /^MemAvailable:/{print $2} /proc/meminfo) MEM_USED_NEW$(( (MEM_TOTAL - MEM_AVAILABLE_NEW) * 100 / MEM_TOTAL )) echo $(date %Y-%m-%d %H:%M:%S) 清理后内存使用率: ${MEM_USED_NEW}% $LOG_FILE else echo $(date %Y-%m-%d %H:%M:%S) 内存使用率未超过阈值跳过清理 $LOG_FILE fi这个脚本几点说明阈值用的MemAvailable来计算比直接用free的used列更合理因为它把可回收缓存算进可用内存了。日志写文件方便回头检查定时任务有没有真正执行。清理后再输出一次结果形成“执行前-执行后”对照。给脚本加执行权限chmod x /usr/local/sbin/clean_mem_cache.sh3.3 为什么我不建议无脑清其实“内存不释放”这句话本身就有点误导。Linux内核对缓存的态度是“能缓存就缓存”这是提升性能的设计。频繁清理会带来三个问题第一清理本身有性能开销。drop_caches会触发大量块回收操作瞬间拉高CPU软中断和锁竞争在IO密集的机器上可能造成几秒到十几秒的请求抖动。第二清理完缓存后访问过的文件需要重新从磁盘读取。如果是一台跑PostgreSQL的机器数据文件、WAL日志原本都缓存在内存里突然清空后性能掉得更明显。第三如果应用进程自身有内存泄漏明天又会涨回来清理缓存只能让你在今天看起来舒服一点不可能解决根本问题。所以脚本里的阈值和日志设计目的就是让清理动作“尽量少干、尽量精准”。4. 定时任务挂载crontab与systemd timer两种玩法4.1 crontab最小方案银河麒麟V10默认带cron服务先确认它在运行systemctl status crond --no-pager如果没启动systemctl enable --now crond然后把脚本挂进crontabcrontab -e我用的配置是每15分钟检查一次*/15 * * * * /usr/local/sbin/clean_mem_cache.sh /dev/null 21这里有个小细节crontab环境里的PATH和登录shell不一样很多脚本在手动执行时正常、被cron执行时却报“command not found”就是因为脚本里用了相对命令而没有写全路径。所以脚本里能写绝对路径的地方我都写绝对路径。修改完配置后可以临时换个方式验证一下任务是否真的触发比如在crontab里追加一条输出当前时间的任务看输出是否正常。或者直接用下面命令查看cron执行日志grep CRON /var/log/cron4.2 systemd timer更精细的方案如果你嫌crontab太简陋或者想享受systemd的日志与依赖管理可以用systemd timer。银河麒麟V10的systemd版本比较新完全支持timer。先写一个service单元/etc/systemd/system/mem-clean.service[Unit] DescriptionClean Memory Cache Service [Service] Typeoneshot ExecStart/usr/local/sbin/clean_mem_cache.sh再写timer单元/etc/systemd/system/mem-clean.timer[Unit] DescriptionRun mem-clean every 15 minutes [Timer] OnCalendar*:0/15 Persistenttrue [Install] WantedBytimers.target启动并启用定时器systemctl daemon-reload systemctl enable --now mem-clean.timer systemctl start mem-clean.timer查看timer是否生效systemctl list-timers mem-clean.timer --no-pagerPersistenttrue的意思是如果机器在应该执行任务的时间点处于关机或休眠状态开机后会立即补执行一次。这一点对服务器非常实用尤其是遇到计划内停机维护后回来系统会自动做一次内存检查清理。4.3 定时任务不生效的常见原因我自己踩过几个坑列出来供参考第一是脚本没有可执行权限。crontab和systemd都可能忽略无执行权限的脚本且不报错。第二是脚本格式问题。在Windows下编辑过的脚本会带CRLF换行符Linux执行时会看到\rbash会报错或行为异常。我在麒麟V10上遇到过ssh到Windows机器上编辑脚本、再拉回Linux执行结果全是bad interpreter的情况。解决方式很简单sed -i s/\r$// /usr/local/sbin/clean_mem_cache.sh第三是selinux或安全模块拦截。银河麒麟V10本身带了一定的安全策略模块如果自定义脚本放在比较奇怪的位置某些安全策略会阻止执行。我建议放在/usr/local/sbin/下面而不是随便丢在/home或/tmp目录。第四crontab默认的mail功能在最小化安装下可能没有配置脚本报错信息会写到cron日志而不是发邮件。所以一定别忘了在crontab配置里加/dev/null 21否则系统会往本地mail队列写一堆东西时间久了也是个隐患。5. 治标之后怎么治本内核参数和服务兜底策略5.1 调整swappiness与page cache回收倾向如果你不想每次都手动或定时清理还可以从内核参数上调整让内存回收更积极。重点看两个参数。vm.swappiness控制内核把页面换到交换分区的倾向默认是60在桌面和服务器上都可以适当调低让系统更倾向于保留物理内存内容而不是频繁换页sysctl -w vm.swappiness10vm.vfs_cache_pressure控制内核回收目录项和inode缓存的倾向。默认100是“和page cache同等回收”调大后会更快丢弃目录项缓存释放Slab内存。对麒麟V10上遇到过目录项缓存越堆越大的情况我一般调到200到300之间sysctl -w vm.vfs_cache_pressure200但这些参数重启后都会失效需要持久化。写进/etc/sysctl.conf或放到/etc/sysctl.d/99-memory-tuning.conf里echo vm.swappiness10 /etc/sysctl.d/99-memory-tuning.conf echo vm.vfs_cache_pressure200 /etc/sysctl.d/99-memory-tuning.conf sysctl --system要说明的是这两项调整不是让系统“释放更多内存”而是让系统更早、更主动地去回收可回收的内存减少突然出现“内存不够用”的概率。5.2 对持续膨胀的服务做内存上限兜底如果定位到是某个服务自身在涨内存仅仅调内核参数肯定不够。我建议在定时脚本里加一个“兜底逻辑”检测指定服务的内存占用超过阈值就重启它。这里要注意一点不要随便重启数据库或者有状态服务除非你确认它有完善的恢复机制。拿Tomcat举例我可以写一段如下逻辑TOMCAT_PID$(pgrep -f org.apache.catalina.startup.Bootstrap | head -1) if [ -n $TOMCAT_PID ]; then TOMCAT_RSS$(awk /VmRSS/{print $2} /proc/$TOMCAT_PID/status 2/dev/null) TOMCAT_RSS_MB$(( TOMCAT_RSS / 1024 )) if [ $TOMCAT_RSS_MB -gt 4096 ]; then echo $(date %Y-%m-%d %H:%M:%S) Tomcat 内存超过4GB准备重启 $LOG_FILE systemctl restart tomcat fi fi基于这个思路你可以把Java服务、消息队列、数据库进程都做成“超阈值自动重启记录日志”的形式。危险操作要谨慎使用但对于无状态服务这套兜底比人肉盯监控靠谱多了。5.3 我的经验和建议最后聊一点实在的。我在这台银河麒麟V10上跑这套脚本已经将近半年稳定解决了“长期运行后内存被缓存吃满、需要人工清理”的问题。尤其配合systemd timer哪怕机器重启过任务也能按周期继续执行比原来人为周末开个终端敲命令省心得多。但我更想强调的是定时清理脚本是应急方案不是最优解。如果你在麒麟V10上长期遇到内存不释放建议先花一周时间做内存监控和日志采集确认到底是内核缓存水位过高还是某个应用/桌面组件在持续膨胀。只有搞清楚根因才能决定是把阈值调低、把swap关掉、调大available还是直接修代码、升级组件版本。我在实际运维中的习惯是先用free、pidstat、/proc/meminfo做好快照再用systemd timer挂上带阈值脚本同时调低swappiness双管齐下。这个顺序也是我推荐的。如果你已经遇到内存告急的情况建议先别急着清缓存把日志和数据保留下来然后按上面的思路一步步排查。本文还有配套的精品资源点击获取