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

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


一、问题背景

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

    [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缓存。在生产环境中,请谨慎使用这些命令,因为清空缓存可能会对性能产生一些瞬时影响。