1. 程式人生 > >記憶體區域與記憶體溢位異常

記憶體區域與記憶體溢位異常

第二章 記憶體區域與記憶體溢位異常

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.