凯发k8天生赢家一触即发

java内存溢出分析方法(eclipse memory analyzer 使用简单入门) -凯发k8天生赢家一触即发

2023-08-17,,

转载至:http://outofmemory.cn/java/jvm/outofmemoryerror-analysis

工具

安装memory analyse tools(mat) 工具, 可以直接在eclipse中安装其相应的插件,安装方法可以参考另一篇eclipse插件汇总

不会用的可以参考一下这个帖子使用 eclipse memory analyzer 进行堆转储文件分析

一些java参数设置

-vmargs:  说明后面是vm的参数,所以后面的其实都是jvm的参数了

-xms20m:  java初始分配的堆内存,此处设置为20m -xmx20m:  java最大允许分配的堆内存,此处设置为20m,同时这样设置表示堆内存不许扩展

-xx:permsize=64m: jvm初始分配的非堆内存 -xx:maxpermsize=128m: jvm最大允许分配的非堆内存,按需分配

-xx: heapdumponoutofmemoryerror: 让虚拟机在出现内存异常时dump出当前内存堆转储快照以便事后进行分析。 带上这种参数之后运行jvm,如果出现相应的内存溢出异常,会在目录下形成一个异常时候的内存dump文件(如java_pid7126.hprof文件),将这个文件使用memory analyse tool工具打开就可以看到当前dump内存空间的分析内容。

-xx: heapdumponctrlbreak:

-xss: 设置虚拟机栈内存容量

获得转储文件的一些方法:

    使用jvm启动时的参数设置,如需要在内存溢出时才获取dump可以使用-xx: heapdumponoutofmemoryerror 或者是希望在某个特定时间获取可以使用 -xx: heapdumponctrlbreak

    使用一些java工具获取 ,如 jmap,jconsole 都可以帮助我们得到一个堆转储文件。

mat工具的一些使用心得:

文件目录

使用mat工具打开获取的java_pid7126.hprof文件后,会自动的形成如下的文件目录:

java_pid7126.a2s.index    
java_pid7126.domin.index
java_pid7126.domout.index
java_pid7126.hprof              //转储堆文件
java_pid7126.idx.index
java_pid7126.inbound.index
java_pid7126.index
java_pid7126.o2c.index
java_pid7126.o2hprof.index
java_pid7126.o2ret.index
java_pid7126.outbound.index
java_pid7126.threads
java_pid7126_leak_suspects.zip //打包的报告,解压后会形成一个有html方式的报告发送给其他人,方便读取
分析方法
分析三步曲:
    对问题发生时刻的系统内存状态获取一个整体印象。

    找到最有可能导致内存泄露的元凶,通常也就是消耗内存最多的对象

    进一步去查看这个内存消耗大户的具体情况,看看是否有什么异常的行为。

具体的分析:
查看报告一:内存消耗的整体状况

在overview上的report中可以选择 leak suspects ,来查看整体对象消耗。下方有一个警告可以看到当前系统自动帮忙分析的怀疑对象。在这个怀疑对象中便可以发现大多数的问题。

查看报告二:分析问题的所在

分析对象为什么没有被回收从而导致一直占用内存。采用根搜索算法来分析对象的事情情况。 点击报告一种怀疑对象的detail,可以看到相应的具体分析报告。

shortest paths to the accumulation point 分析gc根元素到内存消耗聚集点的最短路径。 accumulated objects 查看具体的内存对象信息。

几种经常出现的内存溢出方式

java堆溢出

异常信息: “java.lang.outofmemoryerror”。会跟着进一步提示java heap space.

java.lang.outofmemoryerror: java heap space
dumping heap to java_pid1293.hprof ...
heap dump file created [27559990 bytes in 0.233 secs]
exception in thread "main" java.lang.outofmemoryerror: java heap space
at java.util.arrays.copyof(arrays.java:2245)
at java.util.arrays.copyof(arrays.java:2219)
at java.util.arraylist.grow(arraylist.java:242)
at java.util.arraylist.ensureexplicitcapacity(arraylist.java:216)
at java.util.arraylist.ensurecapacityinternal(arraylist.java:208)
at java.util.arraylist.add(arraylist.java:440)
at com.valentine.jvm.analyzer.exception.heapoom.main(heapoom.java:16)

java堆溢出内存问题分析步骤总结: 1. dump出来堆转储快照 2. 使用mat工具对dump出来的堆转储快照进行分析,重点是确认内存中得对象是否必要的,这样可以分清楚到底是出现了内存泄露(memory leak)还是内存溢出(memory overflow) 3. 如果是内存泄露,进一步通过mat工具分析泄露对象到gc roots的引用链。找到泄露对象是通过怎样的路径与gc roots相关联并导致垃圾收集器无法自动回收的。 4. 如果不存在泄露,那么就是内存中得对象却是都还必须活着,就应当检查虚拟机的堆参数(-xmx与-xms),与机器物理内存对比看是否可以调大,从代码上检查是否存在某些对象生命周期过长、持有状态时间过长的情况,尝试减少程序运行期间的内存。

虚拟机和本地方法栈溢出

在hotspot虚拟机中并不区分虚拟机栈和本地方法栈。到对于hostspot来说-xoss参数(设置本地方法栈大小)是存在的,但实际是无效的,栈容量只由-xss参数决定。

异常情况: * 如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出stackoverflowerror异常 * 如果虚拟机在扩展栈时无法申请到足够的内存空间时,将抛出outofmemoryerror异常

异常信息:

stack length:1891exception in thread "main" 
java.lang.stackoverflowerror
at com.valentine.jvm.analyzer.exception.javavmstacksof.stackleak(javavmstacksof.java:8)
at com.valentine.jvm.analyzer.exception.javavmstacksof.stackleak(javavmstacksof.java:9)
at com.valentine.jvm.analyzer.exception.javavmstacksof.stackleak(javavmstacksof.java:9)
……
at com.valentine.jvm.analyzer.exception.javavmstacksof.stackleak(javavmstacksof.java:9)

在单线程下,无论是由于栈帧太小还是虚拟机栈容量太小,当内存无法分配的时候,虚拟机抛出的都是stackoverflowerror异常。 在多线程下,通过不断的建立线程的方式可以产生内存溢出outofmemoryerror异常。

在多线程情况下,给每个线程分配的内存越大,越容易产生内存溢出异常。由于操作系统分配给每个进程的内存是有限的,32位的windows限制为2gb。虚拟机提供了参数来控制java堆和方法区的这两部分内存的最大值。剩余的2gb减去xmx,再减去maxpermsize,忽略掉很小的程序计数器内存。如果虚拟机进程本身耗费的内存不计算,剩下的内存就是有虚拟机栈和本地方法栈瓜分了。此时如果每个线程分配到的虚拟机栈容量越大,可以建立的线程数量自然就越少,建立线程时就越容易把剩下的内存耗尽。 如果建立过多线程导致的内存溢出,在不能减少线程数或者更换64位虚拟机的情况下,就只能通过减少最大堆或者减少栈容量来获取更多的线程。

出现stackoverflowerror的时候有错误堆栈可以读,即时加入 heapdumponoutofmemoryerror也不会dump异常堆内存。

运行时常量池溢出

如果要项运行时常量池中添加内容,最简单的方法就是使用string.intern()这个native方法。

异常信息:

java.lang.outofmemoryerror: permgen space
dumping heap to java_pid1582.hprof ...
heap dump file created [625411 bytes in 0.018 secs]
exception in thread "reference handler" error occurred during initialization of vm
java.lang.outofmemoryerror: permgen space
<> exception: java.lang.outofmemoryerror thrown from the uncaughtexceptionhandler in thread "reference handler"

从异常中可以看出outofmemoryerror后报的是permgen space,说明是方法区溢出。

方法区溢出

方法区用于存放class的相关信息,如类名、访问修饰符、常量池、字段描述、方法描述等。当大量的类产生时填满方法区,会造成方法去溢出。

方法区溢出也是一种常见内存溢出异常,一个类如果要被垃圾收集器回收,判断条件非常苛刻。

本机直接内存溢出

directmemory容量可通过-xx:maxdirectmemorysize指定,如果不指定,则默认与java堆的最大值(-xmx)一样。

java内存溢出分析方法(eclipse memory analyzer 使用简单入门)的相关教程结束。

网站地图