对Java OutOfMemory异常的探究
Posted 一个后端狗
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了对Java OutOfMemory异常的探究相关的知识,希望对你有一定的参考价值。
Java堆溢出
虚拟机参数:
-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
将堆的最小值和最大值都限制成为20M,-XX:+HeapDumpOnOutOfMemoryError出现内存异常时令java虚拟机Dump堆内存转储快照
代码
1 import java.util.*; 2 3 /** 4 * Created by zcy on 2017/6/11. 5 */ 6 public class TestHeapMemory { 7 8 static class OOMObject{ 9 10 } 11 12 public static void main(String[] args){ 13 List<OOMObject> list = new ArrayList<OOMObject>(); 14 while (true){ 15 list.add(new OOMObject()); 16 } 17 } 18 }
运行出现异常:
java.lang.OutOfMemoryError: Java heap space Dumping heap to java_pid9392.hprof ... Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at java.util.Arrays.copyOf(Arrays.java:3210) at java.util.Arrays.copyOf(Arrays.java:3181) at java.util.ArrayList.grow(ArrayList.java:261) at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:235) at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:227) Heap dump file created [28361944 bytes in 0.134 secs] at java.util.ArrayList.add(ArrayList.java:458) at TestHeapMemory.main(TestHeapMemory.java:15)
为了查看实时堆的使用情况,我们可以安装VisualVM Launcher。
安装请参考http://www.oschina.net/translate/setting-up-visualvm-in-under-5-minutes
使用VisualVM Launcher调试程序(需要在程序中sleep延时),发现堆内存一路上涨,最后崩掉了。
查看dump file,绝大多数内存都被数组占用了
要解决Heap的OutOfMemory,一般的手段是使用内存映像分析工具,分析堆转储文件,重点是确认内存中的对象是否是必要的,也就是要先分清楚到底是出现了内存泄露还是内存溢出。
如果是内存泄露,可以进一步使用工具查看到GC Roots的引用链。于是就能找到泄露对象是通过怎样的路径与GC Roots相关联,导致GC无法自动回收。
如果每个对象都有必要存活着,那么应该检查堆参数(-Xms和-Xmx)是否还可以调大
虚拟机栈和本地方法栈溢出
两种异常:
- StackOverFlow异常:线程请求的栈深度大于虚拟机允许的最大深度。
- OutOfMemory异常:虚拟机扩展栈时无法申请到足够的内存空间。
虚拟机参数:
-Xss128k
代码:
1 /** 2 * Created by zcy on 2017/6/11. 3 */ 4 public class TestStackOF { 5 6 private static int stackLength = 0; 7 8 public static void stackLeak() throws InterruptedException { 9 stackLength++; 10 stackLeak(); 11 } 12 13 public static void main(String args[]) throws Throwable { 14 try{ 15 TestStackOF.stackLeak(); 16 } 17 catch (Throwable e){ 18 System.out.println("stack length is: " + stackLength); 19 throw e; 20 } 21 } 22 }
运行结果:
stack length is: 1102 Exception in thread "main" java.lang.StackOverflowError at TestStackOF.stackLeak(TestStackOF.java:9) at TestStackOF.stackLeak(TestStackOF.java:10) at TestStackOF.stackLeak(TestStackOF.java:10) at TestStackOF.stackLeak(TestStackOF.java:10) ...
最后总结一下:
- 对于StackOverFlow异常:栈深度(1000-2000)绝大多数情况下都够用了。有错误堆栈可以阅读。
- 如果由于建立线程过多导致的内存溢出,可以减少堆容量和每个进程的栈容量换取更多的线程。
方法区和运行时常量池溢出
以上是关于对Java OutOfMemory异常的探究的主要内容,如果未能解决你的问题,请参考以下文章
android 布局之滑动探究 scrollTo 和 scrollBy 方法使用说明