在java程序中总会时不时出现一下OOM的异常,来了解一下具体的相应的异常。
首先得做一些准备工作,比如,如何在eclipse中设置java运行的一些参数:
一、JAVA堆溢出
package outOfMemory;
import java.util.ArrayList;
import java.util.List;
/**
* @author lu
*
*/
public class Test_OutOfMemory {
static class OOMObject{
}
public static void main(String[] args) {
List<OOMObject> list = new ArrayList<OOMObject>();
while (true){
list.add(new OOMObject());
System.out.println("增加一个对象成功!");
}
}
}
运行结果是:
[Full GC (Ergonomics) [PSYoungGen: 7734K->7422K(9216K)] [ParOldGen: 8668K->8668K(10240K)] 16403K->16091K(19456K), [Metaspace: 2659K->2659K(1056768K)], 0.0904742 secs] [Times: user=0.21 sys=0.00, real=0.09 secs]
[Full GC (Allocation Failure) [PSYoungGen: 7422K->7422K(9216K)] [ParOldGen: 8668K->8668K(10240K)] 16091K->16091K(19456K), [Metaspace: 2659K->2659K(1056768K)], 0.0763153 secs] [Times: user=0.25 sys=0.01, real=0.08 secs]
Exception in thread "main" Heap
PSYoungGen total 9216K, used 7606K [0x00000007bf600000, 0x00000007c0000000, 0x00000007c0000000)
eden space 8192K, 92% used [0x00000007bf600000,0x00000007bfd6dbb8,0x00000007bfe00000)
from space 1024K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007c0000000)
to space 1024K, 0% used [0x00000007bfe00000,0x00000007bfe00000,0x00000007bff00000)
ParOldGen total 10240K, used 8668K [0x00000007bec00000, 0x00000007bf600000, 0x00000007bf600000)
object space 10240K, 84% used [0x00000007bec00000,0x00000007bf477390,0x00000007bf600000)
Metaspace used 2689K, capacity 4486K, committed 4864K, reserved 1056768K
class space used 290K, capacity 386K, committed 512K, reserved 1048576K
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)
at java.util.ArrayList.add(ArrayList.java:458)
at outOfMemory.Test_OutOfMemory.main(Test_OutOfMemory.java:19)
二、虚拟机栈和本地方法栈溢出
在虚拟机栈和本地方法栈中可能跑出的异常有StackOverflowError(如果县城请求的栈深度大于虚拟机所允许的最大深度)和OutOfMemoryError(如果虚拟机在扩展栈的时候无法申请到足够的内存空间)两种。
其实在这些地方,存在一些重叠的地方:比如:当栈空间无法继续分配的时候,到底是到达了虚拟机允许的最大深度,还是内存太少了?
有两种测试方法:
1、使用-Xss参数减少栈内存的容量。结果:抛出StackOverflowError异常,异常出现时,输出的对栈深度相应减少(因为-Xss减少了)(下面例子验证了。)
2、定义了大量的本地变量,增加此方法帧中本地变量表的长度。结果:抛出stackOverflowError异常时输出的对栈深度相应缩小。
/**
* @author lu
* VM Args: -Xss 128k
*
*/
public class Test_StackOOM {
private int stackLength = 1;
public void stackLeak(){
stackLength++;
stackLeak();
}
public static void main(String[] args) throws Throwable{
Test_StackOOM oom = new Test_StackOOM();
try{
oom.stackLeak();
}catch(Throwable e){
System.out.println("stack length:"+oom.stackLength);
throw e;
}
}
}
运行结果:
stack length:1933
Exception in thread "main" java.lang.StackOverflowError
at outOfMemory.Test_StackOOM.stackLeak(Test_StackOOM.java:14)
at outOfMemory.Test_StackOOM.stackLeak(Test_StackOOM.java:14)
at outOfMemory.Test_StackOOM.stackLeak(Test_StackOOM.java:14)
at outOfMemory.Test_StackOOM.stackLeak(Test_StackOOM.java:14)
at outOfMemory.Test_StackOOM.stackLeak(Test_StackOOM.java:14)
at outOfMemory.Test_StackOOM.stackLeak(Test_StackOOM.java:14)
但是在多线程的结果下:
package outOfMemory;
/**
* @author lu
* 多线程创建线程导致内存溢出异常
* VM Args : -Xss2M
*/
public class Test_StackOOM_2 {
private void dontStop(){
while(true){}
}
public void stackLeakByThread(){
while(true){
Thread thread =new Thread(new Runnable(){
publicvoid run(){
dontStop();
}
});
thread.start();
}
}
public staticvoid main(String[] args) throws Throwable {
Test_StackOOM_2 oom =new Test_StackOOM_2();
oom.stackLeakByThread();
}
}
则会在不久的将来抛出如下异常:
Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread
at java.lang.Thread.start0(Native Method)
at java.lang.Thread.start(Thread.java:714)
at outOfMemory.Test_StackOOM_2.stackLeakByThread(Test_StackOOM_2.java:21)
at outOfMemory.Test_StackOOM_2.main(Test_StackOOM_2.java:27)