前幾天讀《深入理解Java虛擬機》測試了一下書中所寫的java虛擬機異常的代碼,特在此整理一下。
Java堆溢出
衆所周知,JVM(java虛擬機)中堆是用於存放對象實例的,想要令其發生溢出,只需要不斷創造對象便可。
代碼如下:
public class HeapOOM {
static class OOMObject {}
public static void main(String[] args) {
List<OOMObject> list = new ArrayList<HeapOOM.OOMObject>();
int i = 0;
while (true) {
list.add(new OOMObject());
}
}
}
運行結果:
java.lang.OutOfMemoryError: Java heap space
棧溢出
java中棧分爲兩類:Java虛擬機棧和本地方法棧,java虛擬機棧爲java虛擬機的方法提供服務,而本地方法棧則是爲虛擬機使用的Native方法提供服務。二者的溢出方式均相同,都可分爲兩種:
- 線程請求深度大於虛擬機允許的最大深度,拋出StackOverflowError異常
虛擬機擴展棧時無法申請到足夠的內存空間,就會拋出OutOfMemeoryError異常
棧深度溢出的代碼如下:
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;
}
}
}
運行結果:
stack length:9506
* Exception in thread "main" java.lang.StackOverflowError
棧容量溢出:
此處書中代碼有問題,本人未能成功測試(畢竟是國人寫的書,質量不過關)。真正的測試代碼日後另行附上。。。
運行時常量池溢出
java虛擬機中運行時常量池是java虛擬機中方法區的一部分,用於存放編譯期生成的各類字面量和符號引用。
想要使運行時常量池溢出,需要用到String.intern()這個Native方法。該方法的作用是:如果池中包含此String對象的字符串,則返回池中這個字符串的String對象;否則將此對象所包含的字符串添加到常量池中,並返回此String對象的引用。
代碼如下
public class RuntimeConstantPoolOOM {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
int i = 0;
while (true) {
list.add(String.valueOf(i++).intern());
}
}
}
運行結果“
java.lang.OutOfMemoryError: PermGen space
方法區溢出
方法區用於存放Class的相關信息,如類名、訪問修飾符、常量池、字段描述、方法描述等。這個測試基本方法是產生大量的類去填充方法區。
但由於這個測試書中借用了CGLib項目,本人手上無此項目,故未做測試,先將代碼附上吧:
public class JavaMethodAreaOOM{
public static void main(String[] args){
while(true){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(OOMObject.class);
enhancer.setUseCache(false);
enhancer.setCallback(new MethodInterceptor(){
public Object intercept(Object obj,Method method,Object args,MethodProxy proxy) throws Throeable{
return proxy.invokeSuper(obj,args);
}
});
enchaner.create();
}
}
static class OOMObject {}
}
本機直接內存溢出
本機直接內存拋出異常的代碼如下:
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);
}
}
}
運行結果爲:
java.lang.OutOfMemoryError