本篇文章来说明下虚拟机中的两种常见的异常:堆异常和栈异常
堆异常(内存溢出):堆内存空间不足
错误原因: java.lang.OutOfMemoryError: Java heap space 堆内存溢出
解决办法:设置堆内存大小 // -Xms1m -Xmx10m -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError
代码:
// 虚拟机参数配置:-Xms1m -Xmx10m -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError public static void main(String[] args) { List<Object> listObject = new ArrayList<>(); for (int i = 0; i < 10; i++) { System.out.println("i:" + i); Byte[] bytes = new Byte[1 * 1024 * 1024]; listObject.add(bytes); } System.out.println("添加成功..."); }
控制台日志:
[GC (Allocation Failure) [PSYoungGen: 510K->472K(1024K)] 510K->472K(1536K), 0.0060056 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] [GC (Allocation Failure) [PSYoungGen: 977K->504K(1536K)] 977K->560K(2048K), 0.0161010 secs] [Times: user=0.01 sys=0.00, real=0.02 secs] i:0 i:1 [GC (Allocation Failure) [PSYoungGen: 1401K->504K(1536K)] 5553K->4792K(8704K), 0.0092230 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] [GC (Allocation Failure) [PSYoungGen: 504K->488K(2560K)] 4792K->4784K(9728K), 0.0068819 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] [Full GC (Allocation Failure) [PSYoungGen: 488K->0K(2560K)] [ParOldGen: 4296K->4750K(6656K)] 4784K->4750K(9216K), [Metaspace: 3459K->3459K(1056768K)], 0.0138072 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] [GC (Allocation Failure) [PSYoungGen: 0K->0K(2560K)] 4750K->4750K(9728K), 0.0010024 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [Full GC (Allocation Failure) [PSYoungGen: 0K->0K(2560K)] [ParOldGen: 4750K->4732K(7168K)] 4750K->4732K(9728K), [Metaspace: 3459K->3459K(1056768K)], 0.0216869 secs] [Times: user=0.03 sys=0.00, real=0.02 secs] java.lang.OutOfMemoryError: Java heap space Dumping heap to java_pid7864.hprof ... Heap dump file created [9927860 bytes in 0.041 secs] Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at com.gc.Test03.main(Test03.java:12) Heap PSYoungGen total 2560K, used 102K [0x00000000ffd00000, 0x0000000100000000, 0x0000000100000000) eden space 2048K, 5% used [0x00000000ffd00000,0x00000000ffd19a10,0x00000000fff00000) from space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000) to space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000) ParOldGen total 7168K, used 4732K [0x00000000ff600000, 0x00000000ffd00000, 0x00000000ffd00000) object space 7168K, 66% used [0x00000000ff600000,0x00000000ffa9f368,0x00000000ffd00000) Metaspace used 3490K, capacity 4496K, committed 4864K, reserved 1056768K class space used 382K, capacity 388K, committed 512K, reserved 1048576K Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
这里要注意一点: List<Object> listObject = new ArrayList<>(); 这个初始化也是需要空间,因为它的底层也是数组
如果将list注释掉只需要分配10M的空间就够了,但是如果有list存储,要分配50M,当然条件允许的话,空间分配大些会更好,因为可以减少垃圾回收次数。
栈异常(内存泄漏):
错误原因: java.lang.StackOverflowError 栈内存溢出
栈溢出 产生于递归调用,循环遍历是不会的,但是循环方法里面产生递归调用, 也会发生栈溢出。
解决办法:设置线程最大调用深度
-Xss5m 设置最大调用深度
代码:
public class JvmDemo04 { private static int count; public static void count(){ try { count++; count(); } catch (Throwable e) { System.out.println("最大深度:"+count); e.printStackTrace(); } } public static void main(String[] args) { count(); } }
错误日志:
最大深度:16409 java.lang.StackOverflowError at java.util.HashMap.afterNodeAccess(HashMap.java:1779) at java.util.HashMap.putVal(HashMap.java:657) at java.util.HashMap.put(HashMap.java:612) at java.util.HashSet.add(HashSet.java:220) at java.util.Collections$SynchronizedCollection.add(Collections.java:2035) at java.lang.ClassLoader.checkPackageAccess(ClassLoader.java:508) at com.gc.Test04.count(Test04.java:9) at com.gc.Test04.count(Test04.java:9) at com.gc.Test04.count(Test04.java:9) at com.gc.Test04.count(Test04.java:9)
内存溢出与内存泄漏区别
Java内存泄漏就是没有及时清理内存垃圾,导致系统无法再给你提供内存资源(内存资源耗尽);
而Java内存溢出就是你要求分配的内存超出了系统能给你的,系统不能满足需求,于是产生溢出。
内存溢出,这个好理解,说明存储空间不够大。就像倒水倒多了,从杯子上面溢出了来了一样。
内存泄漏,原理是,使用过的内存空间没有被及时释放,长时间占用内存,最终导致内存空间不足,而出现内存溢出。