排查Linux下内存占用过高但无法找到对应内存占用进程的问题【测试成功】

艺帆风顺 发布于 2025-04-03 66 次阅读


一、问题背景

    某项目运行内存占用异常。

[root@JiJian bakend]# free -m             total       used       free     shared    buffers     cachedMem:         15886      15431        455         24         34       2461-/+ buffers/cache:      12934       2951Swap:         8071          2       8069

二、问题排查

1、查询进程内存占用情况,并排序,未发现异常:

ps aux --sort=-%mem | awk '{print $2, $6/1024 " MB", $11}' | head -n 11

[root@JiJian bakend]#   ps aux --sort=-%mem | awk '{print $2, $6/1024 " MB", $11}' | head -n 11PID 0 MB COMMAND1159 765.434 MB /usr/lib/jvm/java-1.8.0-amazon-corretto//bin/java2964 503.453 MB /opt/kaspersky/kesl/libexec/kesl5057 394.562 MB /usr/sbin/mysqld3838 42.2266 MB /opt/kaspersky/klnagent64/sbin/klnagent2951 34.9102 MB /usr/bin/Xorg3827 32.3945 MB /opt/kaspersky/klnagent64/sbin/klnagent2871 29.1055 MB /usr/bin/python2865 27.4727 MB /usr/bin/python3741 27.1797 MB /temp/YLMonitor/YLMonitor639 26.4492 MB /usr/lib/systemd/systemd-journald

2、查询特定进程的虚拟内存占用情况

ps -p 1159 -o rss,vsz,cmd --sort=-rss,-vsz --no-headers | awk '{print $1/1024,"MB",$2/1024,"MB",$3}'

[root@JiJian bin]# ps -p 1159 -o rss,vsz,cmd --sort=-rss,-vsz --no-headers | awk '{print $1/1024,"MB",$2/1024,"MB",$3}'765.301 MB 10326.3 MB /usr/lib/jvm/java-1.8.0-amazon-corretto//bin/java[root@JiJian bin]# ps -p 2964 -o rss,vsz,cmd --sort=-rss,-vsz --no-headers | awk '{print $1/1024,"MB",$2/1024,"MB",$3}'503.496 MB 1311.21 MB /opt/kaspersky/kesl/libexec/kesl[root@JiJian bin]# ps -p 5057 -o rss,vsz,cmd --sort=-rss,-vsz --no-headers | awk '{print $1/1024,"MB",$2/1024,"MB",$3}'394.562 MB 1608.03 MB /usr/sbin/mysqld[root@JiJian bin]# ps -p 3741 -o rss,vsz,cmd --sort=-rss,-vsz --no-headers | awk '{print $1/1024,"MB",$2/1024,"MB",$3}'27.1797 MB 709.848 MB /temp/YLMonitor/YLMonitor

    可以看到,存在某java程序占用虚拟内存超过10G,该进程或许存在问题。

三、相关措施【待验证】

Java进程占用的内存过大,可以考虑以下一些优化措施:

  1. 调整堆内存大小:通过修改Java虚拟机的-Xms-Xmx参数来调整堆内存大小。减小堆内存大小可以降低内存占用,但需要确保应用程序仍能正常运行。可以通过监控应用程序的内存使用情况来进行调整。

  2. 检查代码:分析应用程序代码,查找内存泄漏或不必要的对象引用。确保在使用完对象后将其及时释放,以避免内存泄漏。

  3. 选择合适的垃圾收集器:根据应用程序的性能需求选择适当的垃圾收集器。某些垃圾收集器可能会更有效地管理内存,并减少内存占用。

  4. 使用内存分析工具:使用工具如Java VisualVM、MAT(Memory Analyzer Tool)等来分析内存使用情况,识别内存泄漏和性能瓶颈。

  5. 减少线程数量:减少不必要的线程和线程池的使用,因为每个线程都会占用一定的内存。

  6. 优化数据结构:选择合适的数据结构和集合类型,以减少内存占用。

  7. 升级到更高版本的Java:一些Java版本可能会提供更好的内存管理和性能优化,考虑升级到最新的Java版本。

  8. 考虑使用压缩类指针:Java 8及更高版本支持使用压缩类指针来减小元数据(Metaspace)的内存占用。

  9. 定期进行性能测试和监控:持续监控应用程序的内存使用情况,并定期进行性能测试,以确保内存占用在可接受范围内。

四、临时解决、待观察【测试成功】

1、先查看内存信息:cat /proc/meminfo

[root@JiJian ~]# cat /proc/meminfoMemTotal:       16267700 kBMemFree:         2694716 kBMemAvailable:    3140684 kBBuffers:           35500 kBCached:           749144 kBSwapCached:         1328 kBActive:          1662432 kBInactive:         985644 kBActive(anon):    1231376 kBInactive(anon):   657568 kBActive(file):     431056 kBInactive(file):   328076 kBUnevictable:           0 kBMlocked:               0 kBSwapTotal:       8265724 kBSwapFree:        8263416 kBDirty:                 0 kBWriteback:             0 kBAnonPages:       1862316 kBMapped:           366572 kBShmem:             25508 kBSlab:             121064 kBSReclaimable:      49432 kBSUnreclaim:        71632 kBKernelStack:        9792 kBPageTables:        66476 kBNFS_Unstable:          0 kBBounce:                0 kBWritebackTmp:          0 kBCommitLimit:    16399572 kBCommitted_AS:    2940700 kBVmallocTotal:   34359738367 kBVmallocUsed:      181448 kBVmallocChunk:   34346814608 kBHardwareCorrupted:     0 kBAnonHugePages:   1224704 kBHugePages_Total:       0HugePages_Free:        0HugePages_Rsvd:        0HugePages_Surp:        0Hugepagesize:       2048 kBDirectMap4k:      219072 kBDirectMap2M:     7120896 kBDirectMap1G:    11534336 kB

2、查看Linux系统内核slab分配器信息。

3、查看dentry(目录项缓存)的信息。

        cat /proc/sys/fs/dentry-state 

[root@JiJian ~]#  cat /proc/sys/fs/dentry-state 23582  10007  45  0  0  0

4、释放系统内存。

echo 2 > /proc/sys/vm/drop_caches

5、查看释放后的内存占用情况,可以看到恢复正常。

[root@JiJian ~]# free -m             total       used       free     shared    buffers     cachedMem:         15886      13252       2633         24         34        706-/+ buffers/cache:      12511       3375Swap:         8071          2       8069

五、命令区别

echo 3 > /proc/sys/vm/drop_cachesecho 2 > /proc/sys/vm/drop_caches 都是用于清空Linux内核中的文件系统缓存(页缓存、目录项缓存和inode缓存)的命令,但它们的行为略有不同:

  1. echo 3 > /proc/sys/vm/drop_caches

  • 这个命令清空文件系统缓存,并且会清空目录项缓存、inode缓存以及页缓存。

  • 它将释放大部分文件系统缓存,包括已缓存的文件数据和文件元数据。

  • 这个命令通常在进行性能基准测试之前使用,以确保测试不受之前缓存的影响,或者在系统性能问题时可能需要释放缓存以解决问题。

  • echo 2 > /proc/sys/vm/drop_caches

    • 这个命令清空文件系统缓存,但只清空页缓存,不会影响目录项缓存和inode缓存。

    • 它只会释放已缓存的文件数据,而不会影响文件元数据(目录项和inode)。

    • 这个命令在需要释放文件数据缓存时使用,但保留文件系统元数据,这对于某些应用和工作负载可能很有用。

    通常情况下,echo 3 > /proc/sys/vm/drop_caches 用于清空全部文件系统缓存,而 echo 2 > /proc/sys/vm/drop_caches 用于清空文件数据缓存。选择使用哪个取决于具体需求,例如你是否需要保留目录项缓存和inode缓存。在生产环境中,请谨慎使用这些命令,因为清空缓存可能会对性能产生一些瞬时影响。