服务器与大带宽专家 · 持牌IDC/CDN/ISP服务商
简米科技官网JIANMI TECH
资讯 2026-10-23 简米科技 3,641 字 9 分钟阅读

服务器内存占用高,如何排查解决?,内存占用过高原因及清理方法

导读先看整体水位,再抓具体进程,最后按业务场景做优化,多数情况下,内存告警不是代码崩了,而是缓存机制、连接数堆积或内存泄漏在作祟,服务器内存占用过高怎么清理:先摸清底细再动手很多人一看到内存报警就急着重启服务或直接kill进程,这其实是比较危险的操作,先诊断,后处理是行业共识,排查的第一步不是清理,而是搞清楚内存到……

先看整体水位,再抓具体进程,最后按业务场景做优化。多数情况下,内存告警不是代码崩了,而是缓存机制、连接数堆积或内存泄漏在作祟。

服务器内存占用过高怎么清理:先摸清底细再动手

很多人一看到内存报警就急着重启服务或直接kill进程,这其实是比较危险的操作。先诊断,后处理是行业共识,排查的第一步不是清理,而是搞清楚内存到底被谁吃掉了。

free命令看全局,别只看最后一行

登录服务器后,第一个要敲的命令是free -h,这里有个常见的认知误区:很多人只看used那一列,发现用了90%就慌了,Linux系统的内存管理机制里,buff/cache占了很大比例是正常现象,这部分内存是内核用来加速文件读写和磁盘缓存的。

判断真实内存压力的关键指标是available列,它代表在不触发swap的情况下,还能启动多少新程序,如果available数值很低,比如低于总内存的10%,那才说明真正吃紧了。

同时要检查swap的使用情况,如果swap的si和so数值一直在跳动,说明系统正在频繁进行内存换入换出,这是内存严重不足的典型信号,比单纯看used数值更准确。

top命令定位吃内存的进程

top命令是排查的第二步,进入top界面后,按M键让进程按照内存占用率从高到低排序,此时重点看前几行:

  • PID:进程唯一标识,后面排查要用
  • RES:常驻物理内存大小,这是进程实际占用的物理内存,比%MEM列更有参考价值
  • SHR:共享内存大小,多个进程共用的部分,不能简单相加计算总量

如果你发现某个进程的RES值异常增长,比如Java进程占了二十几个G,那基本可以锁定目标了。

ps命令二次确认

ps aux --sort=-%mem | head -20可以一次性列出内存占用前20的进程,这里有个细节值得注意:通过ps查看到的进程是静态快照,只能反映当下情况,如果想确认内存是不是持续增长,建议隔5分钟再跑一次同样的命令,对比一下关键进程的RSS数值。

如果同一个进程的内存占用在两次采样之间大幅上涨,基本可以断定有内存泄漏或连接未释放的问题。

排查时顺手做的记录

结合监控工具,比如云平台自带的内存监控图表,查看触发告警的时间点前后,系统有没有出现访问量激增、数据库慢查询、定时任务堆积等关联事件,这一步很关键,因为很多内存问题不是单一因素导致的,需要结合时间线来判断。

服务器内存不足会导致什么问题:区分缓存与真实占用

好,现在你已经通过free命令发现内存确实不够了,接下来需要区分到底是缓存吃掉了内存,还是业务进程真的在疯狂消耗内存。

buffer与cache是帮手,不是祸根

Linux内核会主动把空闲内存用于buff/cache,这是为了提升文件读写效率,当业务程序需要更多内存时,这部分缓存会被内核自动回收并分配给应用程序。

所以当你发现buff/cache占了70%以上时,不需要手动清理,网上流传的echo 3 > /proc/sys/vm/drop_caches这种命令,虽然能强制清缓存,但会导致缓存命中率下降,磁盘IO升高,反而不利于系统稳定性,清完之后过几分钟缓存又会涨回来,属于治标不治本的做法。

真正需要警惕的几个指标

排查时按下图思路逐步定位,就能分清是正常占用还是异常消耗:

  • 进程RSS总量是否持续走高:如果所有进程的RES加起来接近物理内存上限,而cache并不高,说明业务本身内存消耗过大
  • swap使用率是否长期不为0:swap里有东西不代表问题,但持续增长就需要关注
  • 单进程内存是否远超其基线水平:比如固定8G的Java进程突然涨到12G,这里面一定有异常

精确找出内存元凶:按业务场景逐个击破

当确认是业务进程导致内存吃紧,接下来要分场景定位,不同技术栈的排查路径完全不同,不能一概而论。

Java应用内存飙升

Java程序内存占用大,通常是堆内存配置不合理或GC回收不及时,用jstat -gcutil <pid> 1000查看JVM的GC情况,如果FGC(Full GC)频率很高且老年代占用率居高不下,就需要考虑:

  • 调整JVM堆大小参数:-Xms和-Xmx设置要匹配实际情况,不要盲目设置太大或太小
  • 排查线程池配置:不合理的核心线程数和最大线程数会导致大量线程挂起,线程本身很吃内存
  • 利用jmap -heap <pid>导出堆内存快照,用MAT等工具分析是否出现了对象泄漏

MySQL或Redis占用过多

数据库内存持续攀升,先看show processlist;有没有长时间运行的SQL把临时表装进了内存,再检查performance_schema内存统计表,定位具体的内存分配器。

MySQL的innodb_buffer_pool_size参数通常占了内存的大头,这个不是乱设置的:应该在物理内存的50%-70%之间,并同时考虑服务器上其他应用的开销。如果同一台服务器上还跑着应用服务,buffer pool就要适当调小。

Redis如果作为缓存使用,maxmemory策略没配置好,程序会在内存吃紧时走SWAP,性能急剧下降,集群场景下则需要把maxmemory-policy指定为合理的淘汰策略,比如allkeys-lru,避免缓存穿透现象。

PHP-FPM或Nginx进程堆积

PHP-FPM的pm.max_children参数如果设置过大,每个进程占用几十兆内存,几十个进程叠加下来相当可观,排查时用ps aux | grep php-fpm统计一下进程数量,再对比服务器总内存,如果发现每个进程内存占用都偏高,检查一下代码里有没有循环中建立数据库连接没关闭,或者单例模式下缓存了太多数据。

Nginx的worker_processes和keepalive设置不当,也会间接引起内存压力,特别是开启访问日志且不做轮转切割的场景下,缓冲区堆积会吃掉不少内存,所以要注意给Nginx配置日志切割,避免内存被日志缓冲拖累。

长期优化方案:解决内存问题的最终出路

排查完成后顺手清理一下异常进程,这只是临时的救火行为,长期还是要做好下面这些操作。

建立内存基线数据

通过监控系统记录一周以上的内存使用曲线,找出业务高峰和低谷的差异,给每个核心服务设定合理的告警阈值,比如平时内存占用稳定在60%,某次突然跳到85%以上,这就是一个值得关注的异常信号。

利用systemd或容器编排限制内存上限

如果是托管在Kubernetes或Docker环境里的服务,可以给容器设置内存limit,这样即使代码出现内存泄漏,进程也会在触发limit时被杀掉并自动重启,避免拖垮宿主机,相当于给系统上了一道保险。

内核参数调优

守护进程和网络层面的内存清理也不容忽视,以下两个参数根据场景按需调整,不要盲目套用:

  • vm.swappiness:默认是60,如果服务器内存足够大,可以调低到10左右,减少swap使用的倾向,优先使用物理内存让性能更稳
  • fs.file-max:如果服务器需要支撑高并发连接,适当调高文件句柄上限,避免因句柄不足导致连接进程挂起,反而增加内存压力

合理的监控告警分级

把告警分为三个级别,区分不同响应策略能让运维更从容:

  • 普通告警:内存使用率超过80%,记录日志,观察趋势
  • 重要告警:超过90%且持续时间超过10分钟,准备扩容或介入排查
  • 紧急告警:swap开始剧烈波动,或OOM Killer开始工作,立即重启可疑进程或临时扩容

Q&A:服务器内存排查中的常见疑问

清理内存缓存真的能解决服务器内存占用高吗?

手动清理缓存(drop_caches)只能释放内核缓存,不能释放进程占用的内存,如果确认内存问题来源于缓存机制,可以临时操作,但不要依赖。真正解决问题还是要找到占用内存多的具体进程和原因。

服务器内存占用高的常见类型有哪些?

主要分为三类:缓存膨胀(buff/cache占大头)、业务进程内存泄漏(RSS持续增长)、连接数堆积(线程或数据库连接未释放)。

内存占用高时,如何评估是否需要升级服务器配置?

统计一段时间的监控数据,如果内存使用长期处于85%以上且通过代码优化、参数调优后仍无法降下来,同时业务量还在持续增长,那确实可以考虑升级内存容量或对服务做拆分了。调优优先于扩容,扩容是最后一步。


排查服务器内存问题,本质上是一个定量分析的过程,先从系统层面判断真实可用内存,再精确到具体进程,最后结合业务场景做针对性优化。不要被缓存数据迷惑,不要盲目kill进程,不要上来就重启。顺着这条排查链路走下来,绝大多数内存问题都能在心平气和的排查中找到答案,长期坚持做基线监控和容量规划,远比每次告警时救火更有价值。

分享本文
本文为 简米科技官网 原创,已由运维技术专家审核。转载请注明来源:原文链接
售前咨询 服务热线 售后 邮箱