本文的目的有两个:1.OutOfMemoryError与StackOverflowError异常在哪个区域发生,2.解决问题的思路;因工作中发现团队的好多人知道一堆定位工具,但对于定位思路模糊不清,不知道所报异常具体问题在哪里胡乱分析,效率低下,故而总结下文。
一、OutOfMemoryError异常
1.1 Java堆(-Xmx -Xms)
1.1.1标识: java.lang.OutOfMemoryError:heap space(比较常见)
1.1.2产生的原因:1.内存泄漏(Memory Leak)
2.内存溢出(Memory OverFlow)
1.1.3定位手段:可以通过参数-XX:+HeapDumpOnOutOfMemoryError让虚拟机在出现内存异常的时候Dump出当前内存堆转存快照以便进行事后分析。
内存泄漏:查看泄漏对象到GC Roots的引用链,找到泄漏对象是通过什么引用路径、与那些GC Roots想关联,才导致垃圾回收器无法回收他们。
内存溢出:对象是必须存在的,得检查Java虚拟机的堆参数(-Xmx -Xms)设置,与机器的内存对比,看看是否还有向上调整的空间。再从代码上检查是否存在某些生命周期过长的对象,持有状态时间过长,存储设计不合理等情况,尽量减小程序运行的情况。
1.2虚拟机栈与本地方法栈
当虚拟机栈允许动态扩展,当扩展栈的容量无法申请到足够内存时,将抛出OutOfMemoryError,但HotSpot虚拟机选择是不支持扩展,所以除非在创建线程申请内存时因无法获取到足够内存时出现OutOfMemoryError异常,否在在线程运行时不会因扩展而导致内存溢出的。
1.3方法区域运行时常量池溢出(-XX:PermSize -XX:MaxPermSize )
1.3.1标识: java.lang.OutOfMemoryError: PermGen space (经常出现)
1.3.2产生的原因:
1 JDK1.6产生大量运行时常量会导致常量池空间不足会产生PermGen space,JDK1.7之后将运行时常量移至Java堆中所以出现的溢出会是heap space
2.运行时生成大量的动态类,如使用到CGLib,大量的Jsp或是动态生成JSP的应用,如:基于OSGI的应用,方法区会因空间不足产生 PermGen space,到JDK1.8之后方法区用元空间替代,所以不会产生 PermGen space不足异常
备注:元空间必要参数:(-XX:
MetaspaceSiz
-XX:MaxMetaspaceSize)
使用Java 8以后,关于元空间的JVM参数有两个:-XX:MetaspaceSize=N
和 -XX:MaxMetaspaceSize=N
,对于64位JVM来说,元空间的默认初始大小是20.75MB,默认的元空间的最大值是无限。MaxMetaspaceSize用于设置metaspace区域的最大值,这个值可以通过mxbean中的MemoryPoolBean获取到,如果这个参数没有设置,那么就是通过mxbean拿到的最大值是-1,表示无穷大。
由于调整元空间的大小需要Full GC,这是非常昂贵的操作,如果应用在启动的时候发生大量Full GC,通常都是由于永久代或元空间发生了大小调整,基于这种情况,一般建议在JVM参数中将MetaspaceSize和MaxMetaspaceSize设置成一样的值,并设置得比初始值要大,对于8G物理内存的机器来说,一般我会将这两个值都设置为256M
1.3.3 定位手段:根据所报异常类型结合实际业务情况调整各区域大小
1.4本机直接内存溢出(-XX:MaxDirectMemorySize 若不设置默认与-Xmx一致)
1.4.1标识: java.lang.OutOfMemoryError:at.sun.msc.Unsafe.allocateMmory(Native Method)
1.4.2 产生原因:使用DirectByteBuffer分配内存操作,但是xDirectMemorySize不足,如:nio操作可能引起此异常
1.4.3定位手段,查看异常,调整参数,在设置堆内存的时候注意预留直接内存
二 、StackOverflowError(-Xss)出现几率小
2.1标识:StackOverflowError
2.2产生的原因:当线程申请的栈深度大于虚拟机所允许的深度。两种情况1.-Xss所设置值过小,2.定义了大量的本地变量
定位手段:根据异常设置-Xss大小,查看代码中是否有递归用的不合理之处。
来源:CSDN
作者:heijunwei
链接:https://blog.csdn.net/heijunwei/article/details/104294176