堆内存溢出
要想保证堆内存溢出,那么只要不断创建对象并且对象不被回收,那么对象数量到达最大堆限制后就会出现内存溢出的异常了。
虚拟机参数:-Xms20M -Xmx20M -XX:+HeapDumpOnOutOfMemoryError
1 public class HeapOverflowTest { 2 3 public static void main(String[] args) { 4 List<HeapOverflowTest> hofts = new ArrayList<HeapOverflowTest>(); 5 while(true){ 6 hofts.add(new HeapOverflowTest()); 7 } 8 } 9 10 }
结果
java.lang.OutOfMemoryError: Java heap space Dumping heap to java_pid18963.hprof ... Heap dump file created [27465755 bytes in 0.108 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 algorithm.HeapOverflowTest.main(HeapOverflowTest.java:11)
栈内存溢出
java虚拟机规范中描述如果线程请求的栈深度太深,会产生栈溢出,比如无线调用自己的方法。
栈内存溢出有两种情况:
1.线程请求的栈深度超过虚拟机所允许的最大深度,会抛出StackOverflowError异常。
2.如果虚拟机在扩展栈无法申请到足够的内存空间,会抛出OutOfMemoryError异常。
虚拟机参数:-Xss228k
1 public class StackOverflowTest { 2 3 private int stackLength; 4 5 public void stackLeak(){ 6 stackLength++; 7 this.stackLeak(); 8 } 9 10 public static void main(String[] args) { 11 12 StackOverflowTest soft = new StackOverflowTest(); 13 try{ 14 soft.stackLeak(); 15 }catch(Throwable e){ 16 System.out.println("stackLength="+soft.stackLength); 17 throw e; 18 } 19 } 20 21 }
结果
stackLength=1517 Exception in thread "main" java.lang.StackOverflowError at algorithm.StackOverflowTest.stackLeak(StackOverflowTest.java:8) at algorithm.StackOverflowTest.stackLeak(StackOverflowTest.java:9) at algorithm.StackOverflowTest.stackLeak(StackOverflowTest.java:9) at algorithm.StackOverflowTest.stackLeak(StackOverflowTest.java:9)
如果不断地建立线程的方式会产生OutOfMemoryError。操作系统分配给进程的内存是有限制的,比如32位windows是2GB。虚拟机提供了参数来控制java堆和方法区两个部分内存的最大值,剩余内存为2GB-最大堆容量-最大方法区容量-程序计数器(很小,可以忽略),虚拟机进程本身
的消耗不考虑,剩下的都是栈内存了。栈内存是线程私有的,那么每个线程分配的栈容量大,那么建立的线程数必然减少,所以很容易把剩下的内存耗尽。虚拟机默认参数,栈深度1000~2000没什么问题,正常方法应该问题不大。如果建立了过多线程导致的OutOfMemoryError,在不能
减少线程或者更换64位虚拟机的情况下,只能通过减少最大堆容量和减少栈容量来换取更多的线程了。
方法区和运行时常量池溢出
1 public class ConstantPoolOverflowTest { 2 3 public static void main(String[] args) { 4 List<String> list = new ArrayList<String>(); 5 int i =0; 6 while(true){ 7 list.add(String.valueOf(i++).intern()); 8 } 9 } 10 }
结果
Error occurred during initialization of VM java.lang.OutOfMemoryError: PermGen space at sun.misc.Launcher.<init>(Launcher.java:71) at sun.misc.Launcher.<clinit>(Launcher.java:57) at java.lang.ClassLoader.initSystemClassLoader(ClassLoader.java:1489) at java.lang.ClassLoader.getSystemClassLoader(ClassLoader.java:1474) Exception in thread "Reference Handler"
对于Hotspot来说,方法区=永久代。