JVM内存溢出查询java.lang.OutOfMemoryError: Java heap space查出具体缘由分为几个预备步骤java
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/dump_OOME.hprof 当内存溢出时 会输出在/tmp/dump_OOME.hprof目录下api
#jvm options #JAVA_OPTS="-Xms8192m -Xmx8192m -Xmn4096m -Djava.awt.headless=true -XX:MaxPermSize=512m -server -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=85 -XX:+DisableExplicitGC -Xnoclassgc -Xverify:none" JAVA_OPTS="-Xms4096m -Xmx4096m -Djava.awt.headless=true -XX:MaxPermSize=512m -server -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=85 -XX:+DisableExplicitGC -Xnoclassgc -Xverify:none" JAVA_OPTS="$JAVA_OPTS -javaagent:/usr/local/src/sflowagent.jar -Dsflow.hostname=platform -Dsflow.dsindex=10000" JAVA_OPTS="$JAVA_OPTS -XX:+PrintGC -XX:+PrintGCDateStamps -XX:+PrintGCDetails -Xloggc:/tmp/gc.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=10M" JAVA_OPTS="$JAVA_OPTS -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/dump_OOME.hprof"
MemoryAnalyzerTool(也叫MAT)是一款JAVA虚拟机内存映像分析工具,less
能够在JAVA程序运行的时候有程序抛出的异常加上已经设置好的参数(-XX:+HeapDumpOnOutOfMemory)调试出内存泄漏或者异常的位置以及缘由跟踪,eclipse
MemeoryAnalyzer能够对Dump出来的堆转储快照进行分析,重点是确认内存中的对象是不是有必要的,也就是要先确认究竟是出现了内存泄漏(Memory Leak)仍是内存溢出(Memory OverFlow)。jvm
运行Eclipse,而后单击菜单栏上“Help=》Install New Software...”工具
进入软件源导入界面,你能够选择使用URL直接导入,URL导入的地址为:测试
http://download.eclipse.org/mat/1.7/update-site/
可是因为镜像链接不稳定性,我使用的是下载压缩包zip而后安装,压缩包下载地址为:http://ftp.jaist.ac.jp/pub/eclipse/mat/1.7/MemoryAnalyzer-1.7.0.201706130745.zipspa
下载完成以后将其导入,"Add》Archive》选择你下载好的zip文件》OK":插件
肯定以后勾选"Memory Analyzer for Eclipse IDE"下面的两项便可,这个是用于Eclipse内部使用的插件,下面一个“Stand-alone Memory Analyzer“是独立的分析工具,通常不用勾选。调试
以后单击“Next"等待一段时间Eclipse计算的需求和依赖文件下载完毕后,一路"next",并接受协议“Finish”便可完成安装,重启Eclispe后就可使用MAT了。
JVM的参数能够用于调试JVM在各类限制条件下的常见BUG,一下简单介绍几个参数:
-XX:+HeapDumpOnOutOfMemoryError //虚拟机在堆异常时生成对存储快照,后缀通常是.hprof -Xms //Java堆的最小值,例如-Xms20m,将Java堆的最小值设置为20MB -Xmx //Java堆的最大值,例如-Xms40m,将Java堆的最大值设置为40MB
了解了参数以后,能够对参数进行必定的设置,以便咱们简单的对MAT工具进行使用测试,设置参数以下:
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=D://dump_OOME.hprof -Xms20m -Xmx20m
之因此将最小和最大的堆设置为同样是为了能避免堆的自动扩展,以及20MB的空间是为了让程序能尽快的占满使得内存溢出。
设置JVM的启动参数可在“Run》Run Configuration》Arguments》Vm arguments”中填写
思路:经过新建集合列表List,而后以while(true)死循环的方式使得List集合不断添加新的对象,使得其不断地占满堆空间
代码:
package com.study; import java.util.ArrayList; import java.util.List; public class TestStudy { static class OOMClass { } public static void main(String[] args) { List<OOMClass> list = new ArrayList<OOMClass>(); while(true) { list.add(new OOMClass()); } } }
执行代码,发现输出以下:
注意到“java_pid24792.hprof”文件,这个文件是JVM生成的对存储快照,以后能够经过MAT工具打开,进行分析追踪,这个文件将自动保存到你的Eclipse workspace下的工做目录中,以个人为例:
因为MAT工具须要另外打开一个工做视图(就像Eclipse EE和Java的切换视图同样),所以须要在先配置打开"Window》Perspective》Open Perspective》Other...":
选择Memory Analysis并肯定:
完后以后将进入MAT的工做空间视图,你能够在Eclipse右上角进行切换回Java或者EE,因为接下来要使用MAT分析,所以就暂时不切回以前的Java了
因为MAT是依赖于生成的堆转储快照,而不是在运行的时候自动捕获,所以,再确认进入MAT的工做空间后,点击"File》Open Heap Dump》选择刚生成的“java_pid24792.hprof”文件,一直默认就能够查看内存问题的分析图表以及GC根
你能够进行一些分析操做,能够看到Action下的几个选项:
a.Histogram:列出每一个类的实例列表;
b.Dominator:列出最大的对象和他们存在的东西;
c.Top Comsumer:打印按类和包分组的最昂贵的对象;
d.Duplicate Classes:检测由多个类加载器加载的类。
因为是一个简单的问题,所以咱们直接选择Dominator,能够直接以百分比的形式打印出对象所占的百分比,通常的内存溢出大部分状况都是有某一个对象过多存在而未被GC回收致使,因此能够点开最大百分比的类一级级找,不难找到问题所在:
能够看到列出额其中的25条,还有810300条目未列出,这81万个对象占据了97.36%的堆空间,所以不难发现是OOMClass类的对象生成过多为未被回收致使内存溢出。
在"default_report org.eclipse.mat.api:suspects"的标签分页中
在"Program Suspect 1》Details"点击后找到"Thread Stack"中追踪出错点
看到出错点在第13行,找到对应的Java代码TestStudy的13行:
1 package com.study; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 public class TestStudy { 7 8 static class OOMClass { } 9 10 public static void main(String[] args) { 11 List<OOMClass> list = new ArrayList<OOMClass>(); 12 while(true) { 13 list.add(new OOMClass()); 14 } 15 } 16 17 }
找到了追踪的出错位置,以上就是使用Memory Analyzer工具完成的堆栈分析。