記憶體區域與記憶體溢位異常
阿新 • • 發佈:2018-11-27
第二章 記憶體區域與記憶體溢位異常
2.2 執行時資料區域
2.2.1 程式計數器
程式計數器是當前程式執行的位元組碼的行號指示器,通過改變程式計數器的值可以實現 分支,跳轉,迴圈,異常,執行緒回覆等功能
### 2.2.2 Java虛擬機器棧和本地方法棧
執行緒私有,與執行緒的生命週期相同。方法執行時在此處建立棧幀用於儲存區域性變量表,運算元棧,動態連結,方法出口的那個資訊。
2.2.3本地方法棧
也是執行緒私有,與執行緒生命週期相同。它為執行本地方法提供服務
2.2.4 java堆
被所有執行緒共有,可以分為Eden ,From Survivor ,To Survivor .建立物件時在堆上分配記憶體,也是垃圾收集器管理的主要區域。
2.2.5方法區
所有執行緒共享,用於儲存虛擬機器載入的類資訊、常量、靜態變數、即時編譯器編譯後的程式碼等資料。在HotSpot中也被稱為永久代
2.2.6執行時常量池
它是方法區的一部分,用於存放編譯期生成的各種字面量和符號引用。執行期可以使用String.intern()方法使字元進入常量池
2.2.7直接記憶體
我覺得就是本機記憶體,沒有什麼特別的。
2.3物件
2.3.1物件的建立
先檢查這個指令的引數是否能在常量池中定位到類的符號引用,並且檢查符號引用的類是否被載入,解析,初始化,如果沒有就去載入。然後分配記憶體,初始化為0值,設定元資料資訊,物件的hash碼,GC分代年齡,。
2.4實戰
2.4.1 java 堆溢位
package memoryTest; /** * VM Args:-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError * @author 洪buff */ import java.util.ArrayList; import java.util.List; public class HeapMain { static class OOMObject{ } public static void main(String[] args){ List<OOMObject> list=new ArrayList<OOMObject>(); while(true){ list.add(new OOMObject()); } } }
2.4.2本地方法棧和虛擬機器棧溢位
package memoryTest;
/**
* VM Args: -Xss128K
* @author 洪buff
*
*/
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;
}
}
}
### 2.4.3本地方法棧溢位
package memoryTest;
/**
* VM Args:-Xss2M(或者更大)
* @author 洪buff
*
*/
public class JavaVMStackOOM {
private void dontStop(){
while(true){
}
}
public void stackLeakByThread() {
while (true){
Thread thread =new Thread(new Runnable(){
@Override
public void run() {
dontStop();
}
});
thread.start();
}
}
public static void main(String[] args) {
JavaVMStackOOM oom=new JavaVMStackOOM();
oom.stackLeakByThread();
}
}
很危險,我不做演示
2.4.3方法區和執行時常量中intern
package memoryTest;
public class RuntimeConstanPoolOOM {
public static void main(String[] args) {
String str1=new StringBuilder("計算機").append("軟體").toString();
System.out.println(str1.intern()==str1);
String str2=new StringBuilder("ja").append("va").toString();
System.out.println(str2.intern()==str2);
}
}
分析:StringBuilder在堆中建立字串物件“計算機軟體",intern()方法將它的引用複製到了字串常量池,所以答案是true.
"java"第一次被建立是在類載入時,在常量池中載入,而str2則是指向堆中的”java"物件,intern()方法返回的時常量池中的“java"所以答案是false.