内存溢出之后,分析原因往往有些困难,这里在启动jvm的时候可以增加一些参数,等内存溢出发生时jvm会帮我们记录当时的快照
这是我模拟内存溢出的启动参数:
-Xmx64m -Xms32m -Xmn16m -Xss8m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/Users/liucheng/开发/vm/VMDemo.hprof -XX:OnOutOfMemoryError="/Users/liucheng/开发/vm/sh/clear.sh VMDemo"
设置jvm的内存大小相关参数我不说了,重点是后面几个参数
-XX:+HeapDumpOnOutOfMemoryError 当jvm发生内存溢出(om溢出)的时候进行快照记录;
-XX:HeapDumpPath 设置快照路径(可以是路径,也可以是具体到快照文件名),如果不设置,默认会在当前工作空间生成快照。
-XX:OnOutOfMemoryError 设置发生内存溢出后调用一个sh脚本(调用脚本更多的目的是将快照文件转移到其他服务器,因为快照文件非常大,经常发生om又没有及时清理快照文件,会很快让磁盘被塞满)
ok,开始正题,导致堆内存溢出的代码:
执行结果:
附上clear.sh脚本:
生成的快照文件:
如何分析快照文件,这里我推荐3种方式:
一、使用java自带的命令 jhat
这种方式会将快照信息以web的方式展现,但是展示信息有限。
浏览器访问 http://localhost:7000
这里面每个链接操作都有相应的说明,有兴趣的可以百度了解,这种方式我不太喜欢,没有过多了解
二、使用mat工具分析
在这里下载 https://www.eclipse.org/mat/
mat载入快照文件后:
这个把内存情况用饼形图表达的很清楚。
更多信息
通过上面这张图可以看出代码中的 list塞入了1407条类型为string的数据
三、使用visualVM
装载进快照文件后,选择线程项
以上是都是快照已经生成,事后来找问题的方案,针对正在运行中的jvm来说,可以用以下方式监控jvm各种参数起到调试作用。
一、使用visualVM
这种方式我就不多说了,除了本地也可以远程连接,这种都懂,下面我要介绍的是才是好用的
二、使用java自带的jconsole工具
运行 jconsole 稍等一下下出来一个界面
这次连接一个远程的jvm来示例
远程连接之前的准备工作:
这里公网ip就不对外公开了,我用本地hosts al.cloud.net映射了公网服务器ip,设置成你自己要连接的服务器上公网ip即可。
以下是参数解释
本地来测试一下服务器上的端口是否可以正常通信 telnet al.cloud.net 9990
开始连接
出现这个是因为ssl项设置为false了 不管它继续点击连接
后面的都知道操作了。
其实还有一些java自带的命令方式查看
比如:
- S0C : survivor0区的总容量
- S1C : survivor1区的总容量
- S0U : survivor0区已使用的容量
- S1C : survivor1区已使用的容量
- EC : Eden区的总容量
- EU : Eden区已使用的容量
- OC : Old区的总容量
- OU : Old区已使用的容量
- PC 当前perm的容量 (KB)
- PU perm的使用 (KB)
- YGC : 新生代垃圾回收次数
- YGCT : 新生代垃圾回收时间
- FGC : 老年代垃圾回收次数
- FGCT : 老年代垃圾回收时间
- GCT : 垃圾回收总消耗时间
- NGCMN : 新生代占用的最小空间
- NGCMX : 新生代占用的最大空间
- OGCMN : 老年代占用的最小空间
- OGCMX : 老年代占用的最大空间
- OGC:当前年老代的容量 (KB)
- OC:当前年老代的空间 (KB)
- PGCMN : perm占用的最小空间
- PGCMX : perm占用的最大空间
- LGCC:最近垃圾回收的原因
- GCC:当前垃圾回收的原因
- Compiled : 编译数量
- Failed : 编译失败数量
- Invalid : 无效数量
- Time : 编译耗时
- FailedType : 失败类型
- FailedMethod : 失败方法的全限定名
- Loaded : 加载class的数量
- Bytes : class字节大小
- Unloaded : 未加载class的数量
- Bytes : 未加载class的字节大小
- Time : 加载时间