寻找不知去向的内存

122 阅读3分钟

起因

最近一个生产运行特别稳定的系统突然报警,报警的原因不是CPU过高,而是交换区内存小于20%。这台服务器配置的是如果物理内存使用率超过70%则使用开始使用虚拟内存。服务器的配置为4C8G,并且配置了8G的交换区(SWAP)。这台服务器是一个java后端应用,主要用于会话同步。

查询

在遇到这个问题时,我们首先需要登录服务器,进行top、free二连。在top命令时,我们需要看一下除了我们自己的应用,是否还有其他应用在占用内存。

    top

然后按M,让他按照内存进行排序(这里涉及一些具体应用名就不贴图了)。在top命令中,你可以看到总的内存以及闲置的内存。然后我们可以看到除了我们自己的内存确实还有个进程实用内存,但是我们的应用占了77%,那个应用最多才3%。那就好了,锅已经背在了背上。

然后使用free命令,查询总内存,实用内存以及空闲内存

    free -h

image.png

确实这台服务器的占用内存情况非常的恶劣,我们要开始查具体的说明情况了。

在linux中,所有都是文件,所以在你启动一个进程时,会在 /proc 这个目录下生成一个控制内容。例如你的pid是443,那么你就可以去 /proc/443 目录下看看。其中的status是你进程使用的基本信息。

image.png 从这个地方你就可以找到当前进程使用的物理内存以及虚拟内存大小了。其中VmRSS为物理内存大小,这里大概是6G,VmSwap为虚拟内存空间大小,这里也大概是6G左右。然后我们开始怀疑是否是我们内存泄漏了。所以打算拿堆栈信息。

通过jvm的命令,首先我们看栈信息,发现一切都是正常的,日志也没有任何的问题,不应该是栈内数据不断创建,或者栈内数据太多导致的。所以我们开始怀疑是不是堆的问题。会不会是堆的问题。所以我们拿了堆记录,通过mat进行分析。

首先没有OOM问题,但还是查看一下吧。

image.png 这图,正常的不能再正常,然后我们查看了一下堆内对象:

image.png 才409M。我们的应用占了这么大的空间,但是内存不是因为堆,也不是因为栈,那我们的内存呢?

学过jvm的同学会反应过来,有一部分数据不会在这个里面,就是堆外内存,我们查询下是否有相关类:

image.png

在启动中,如果没有配置MaxDirectMemorySize的,MaxDirectMemorySize的大小即等于-Xmx。而我们启动的时候使用的脚本

    java -Xms6144m -Xmx6144m xxx.jar

解决

根据上面一波分析,我们将在下次启动的时候要额外增加MaxDirectMemorySize,调整具体的大小,当他达到上限时触发FGC,从而进行垃圾回收。

    java -Xms6144m -Xmx6144m - XX:MaxDirectMemorySize=2048m xxx.jar