JVM內存結構簡單認知

關於JVM的面試傳送門:http://www.javashuo.com/article/p-fhbpjqer-ha.htmlhtml

JVM內存結構主要劃分爲:堆,jvm棧,本地方法棧,方法區,程序計數器java

以下圖所示:面試

堆區:

簡單概述:每一個Java項目都有惟一對應的一個JVM實例,每個JVM實例又對應着一個堆區。Java堆是被當前應用全部進程所共享的,在JVM啓動時就建立了。堆區的目的就是存放全部new建立實例對象和數組,因而可知堆對於當前應用來講是全局的。數組

  PS:這也就解釋了假設有A,B兩個Java項目,A項目有a,b,c三個類,a類能夠調用b,c三個類,可是在B項目就不能夠使用a,b,c三個類了數據結構

堆區的特色堆的主要優點是靈活性,它能夠的動態的分配內存。編譯器不須要知道須要建立對象的時候須要分配多少內存給它,也不須要知道該對象的生命週期。new一個對象的時候會自動從堆中分配內存給它,而後若是長時間沒有引用指向該對象時,JVM垃圾回收機制會在某個合適的時間點回收它。jvm

Java堆是jvm管理內存中最大的一塊,它也是JVM垃圾回收的主要區域。雖然JVM垃圾回收機制會在某個合適的時間點自動回收沒有引用指向的對象,可是做爲java開發人員,掌握垃圾回收機制是很重要的,往後還要去學習這個....函數

本地方法棧:

虛擬機執行Native方法服務,執行不是用Java代碼寫的如C寫的學習

虛擬機棧區:

  當程序進入到一個方法時,會爲這個方法分配一個私有存儲空間,該空間爲JVM棧。該線程爲私有的。就比如你在a()方法中定義了int t = 1;可是在b方法中就不能直接用t。可是棧裏面的數據是能夠共享的。當方法結束時,該區域就釋放了spa

  棧的速度比堆要快,僅次於寄存器。可是缺乏靈活性,其數據大小和生存週期可知(這些字面值固定定義在某個程序塊裏面,程序塊退出後,字段值就消失了).net

  至於爲何函數調用要採用棧調用,主要是契合數據結構中棧的先進後出原則,能夠看下這篇鏈接:https://www.zhihu.com/question/34499262/answer/59415153

  實例分析一:棧裏面的數據是共享的

  int a=1;

  int b=1;

  編譯器預先處理int a =1;首先在棧中建立一個變量爲a的引用,而後去棧中查找有沒有字面值爲1的地址,沒有就開闢一個存放字面值爲1的地址。接着執行b=1;建立一個變量爲b的引用,因爲已經存在字面值爲1的地址了,因此b直接指向該地址。因此:出現了a,b同時指向1這個地址

  特別注意:字面值的引用與對象的引用是不同的,假設兩個類對象的引用指向同一個對象,若是一個引用對象修改了這個類的內部狀態,那麼另外一個引用對象也會便可反映出這個變化;而字面值引用則不會,假設在寫上b=2,那麼b引用會從新去JVM棧中去尋找字面值爲2的地址,找不到則從新開闢一個地址來存儲2,而後b引用在指向它

public class test2 {

    public static void main(String[] args) {
        int a = 1;
        int b = 1;
        // 1.建立變量爲a的引用,在JVM棧中開闢字面值爲1的地址,a在指向它
        // 2.建立變量爲b的引用,棧中已存在字面值爲1的地址,b直接指向該地址。因此a,b地址相同
        System.out.println(a == b);    //true
        b = 2;
        System.out.println(a==b);    //false
    }

}
public class test {

    int num = 1;

    public static void main(String[] args) {
        // 建立變量爲a的對象引用,new test()在堆中分配內存存儲該對象,a再指向堆區中該對象的地址
        test a = new test();
        // 建立變量值爲b的引用對象,指向a指向的堆區中地址
        test b = a;
        System.out.println(a == b); 
        b.num = 2;
        //這裏就屬於另外一個對象引用修改了該對象的內部狀態,致使a受影響了
        System.out.println(a.num); // 2 若是是test b = new test()則輸出1,由於指向的不是同一個對象

        // 這裏又在堆區中給test對象分配了內存
        test c = new test();
        System.out.println(a == c); 
    }

}

 關於包裝類型數據:如Integer,Double,Float等將基本數據類型包裝起來的類,它們存在於堆區中。Java用new()來顯示的告訴編譯器要建立。以後將對包裝類型作一下整理,尤爲是地址指向

http://www.blogjava.net/hgc-ghc/archive/2013/05/02/398675.html

方法區:

  方法區也同堆同樣是被全部線程所共享的,它裏面存放着satic修飾的代碼和類信息,常量(final修飾)

程序計數器:

線程私有,佔用內存小。

字節碼行號指示器,解釋器經過它來選取下一條執行的字節碼指令

  • 執行 Java 方法:具體的內容就是指向下一個指令的偏移
  • 執行 Native 方法:計數值爲空(undefined)

不會有 OutOfMemoryError

相關文章
相關標籤/搜索