1. 運行時數據區域
程序計時器:線程私有的,在操作系統結構中,程序計數器是用於存放下一條指令所在單元的地址的地方。在JVM是一塊較少的內存空間,他的作用可以看做是當前線程所執行的字節碼的行號指示器。字節碼解析器工作時就是通過改變這個計算器的值來選取下一條需要執行的字節碼指令。
Java虛擬機棧:是線程私有的,他的生命週期與線程相同,每個方法執被執行的時候都會同時創建一個棧幀,用於存儲局部變量表、操作棧、動態鏈接、方法出口。
本地方法棧:爲java中的Native方法服務。
Java堆:所有線程共享的內存區域,存放對象的實例與數組。堆還可以分爲新生代與老年代。新生代細分爲Eden空間、FromSurvivor空間、To Survivor空間。
Java方法區:所有線程共享,用於存儲jVM加載的類信息、常量、靜態變量等。
運行時常量:隸屬於方法區,用於存在編譯期生成的各種字面量和符號引號。
2. 實戰:OutOfMemoryError異常
2.1 Java堆異常
代碼清單1:
package com.one.jvm;
import java.util.ArrayList;
import java.util.List;
public class HeapOut {
static class ObjectOut {
}
public static void main(String[] args) {
List<ObjectOut> ObjectOuts = new ArrayList<HeapOut.ObjectOut>();
while(true) {
ObjectOuts.add(new ObjectOut());
}
}
}
2.2 虛擬機棧和本地方法棧溢出
在Java虛擬機規則中描述了兩種異常
1、如果線程請求的棧深度大於虛擬機所允許的最大深度,將拋出StackOverflowError異常
2、如果虛擬機擴展棧時無法申請到足夠的空間,則拋出OutOfMemoryError異常
代碼清單2:
package com.one.jvm;
public class StackOverflow {
private int count = 1;
public void countAdd() {
count++;
System.out.println(count);
countAdd();
}
public static void main(String[] args) throws Throwable{
new StackOverflow().countAdd();
}
}
2.3 運行時常量異常
代碼清單3:
package com.one.jvm;
import java.util.ArrayList;
import java.util.List;
public class ConstantPoolOut {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
int i = 0;
while(true) {
list.add(String.valueOf(i++).intern());
}
}
}
2.4 方法區溢出
代碼清單4:
package com.one.jvm;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class JavaMethodOut {
public static void main( String[] args) {
while(true) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(ClassObject.class);
enhancer.setUseCache(false);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object arg0, Method arg1, Object[] arg2,
MethodProxy arg3) throws Throwable {
return arg3.invokeSuper(arg0, arg2);
}
});
enhancer.create();
}
}
static class ClassObject {
}
}