在Java虚拟机范例形貌中,除了顺序计数器外,虚拟机内存的其他几个运转地区都有发作 OOM 非常的能够。在这里,用代码考证各个运转时地区存储的内容并议论该如何举行处置惩罚。
Java堆溢出
Java 堆用于存储对象实例,只需不停竖立对象,而且保证 GC Roots 到对象之间有可达门路来防止垃圾接纳机制消灭这些对象,那末对象数目到达最大堆的容量限定以后就会发生内存溢出非常。
非常再现
代码采纳以下虚拟机参数:
-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
如许 Java 堆的大小将被限定为20 MB 且不可拓展。经由过程参数 -XX:+HeapDumpOnOutOfMemoryError 能够让虚拟机在涌现内存溢出非常时 Dump 出当前的内存堆转储快照以便时刻举行剖析。
采纳以下代码举行考证:
public class HeapOOM { static class OOMObject { } public static void main(String[] args) { List<OOMObject> list = new ArrayList<OOMObject>(); while (true) { list.add(new OOMObject()); } } }
运转效果:
java.lang.OutOfMemoryError: Java heap space Dumping heap to java_pid3460.hprof ... Heap dump file created [28199779 bytes in 0.237 secs]
处理要领
Java 堆内存的 OOM 非常是现实运用中常见的内存溢出非常状况,涌现时往往会紧跟着提醒“Java heap space”。
要处理这个地区的非常,平常的手腕是先经由过程内存映像剖析东西,比方 MAT ,确认究竟是涌现了内存走漏照样内存溢出。
假如是内存走漏,能够进一步经由过程东西检察走漏对象到 GC Roots 的援用链,找到走漏对象是经由过程如何的门路和 GC Roots 相干联并致使垃圾收集器没法自动接纳它们所占的空间。
假如不是内存走漏,换而言之,内存中的对象确切另有必要存在世,那末就应当搜检虚拟机的堆参数,与机械物理内存对照看是不是还能够调大。从代码层面上看,是不是存在某些对象生命周期太长、持有状况时候太长的状况,尝试削减顺序运转时期的内存斲丧。
虚拟机栈和当地要领栈溢出
由于在 HotSpot 虚拟机中并不辨别虚拟机栈或许当地要领栈,因而关于 HotSpot 而言,虽然 -Xoss 参数存在,然则现实上是无效的,栈容量只由 -Xss 参数设定。
非常再现
在单线程下,代码采纳以下的虚拟机参数:
-Xss128k
运用该参数减小栈容量,运用以下代码复现非常:
public class JavaVMStackSOF { private int stackLength = 1; public void stackLeak() { stackLength++; stackLeak(); } public static void main(String[] args) throws Throwable { JavaVMStackSOF oom = new JavaVMStackSOF(); try { oom.stackLeak(); } catch (Throwable e) { System.out.println("stack length:" + oom.stackLength); throw e; } } }
处理要领
假如运用虚拟机默许参数,栈深度在大多数状况下(由于每一个要领压入栈的帧大小并非一样的,所以只能说在大多数状况下)到达1000 ~ 2000 完整没有问题,关于一般的要领挪用(包含递归),这个深度应当完整充足。
然则,假如是由于竖立过量的线程致使内存溢出,在不能削减线程数或许替换64位虚拟机的状况下,就只能经由过程削减最大堆和削减栈容量来调换更多的线程。
本机直接内存溢出
DirectMemory 容量能够经由过程 -XX :MaxDirectMemorySize 指定,假如不指定,则默许与Java最大堆一样。
非常再现
运用以下虚拟机参数:
-Xmx20M -XX:MaxDirectMemorySize=10M
运用以下代码重现非常:
public class DirectMemoryOOM { private static final int _1MB = 1024 * 1024; public static void main(String[] args) throws Exception { Field unsafeField = Unsafe.class.getDeclaredFields()[0]; unsafeField.setAccessible(true); Unsafe unsafe = (Unsafe) unsafeField.get(null); while (true) { unsafe.allocateMemory(_1MB);//直接请求分派内存 } } }
处理要领
由 DirectMemory 致使的内存溢出,一个显著的特性就是在Heap Dump 文件中不会瞥见显著的非常。
假如发明 OOM 以后Dump文件很小,而顺序中又直接或许间接运用了NIO ,那末就能够斟酌搜检一下是不是是这方面的缘由。
以上就是Java非常之OutOfMemoryError的处理要领的细致内容,更多请关注ki4网别的相干文章!