關于JVM結構的學習

jopen 10年前發布 | 14K 次閱讀 JVM Java開發


JVM內部結構圖
</div>


關于JVM結構的學習

Java虛擬機主要分為五個區域:方法區、堆、Java棧、PC寄存器、本地方法棧。下面

來看一些關于JVM結構的重要問題。


1.哪些區域是共享的?哪些是私有的?


Java棧、本地方法棧、程序計數器是隨用戶線程的啟動和結束而建立和銷毀的,

每個線程都有獨立的這些區域。而方法區、堆是被整個JVM進程中的所有線程共享的。

關于JVM結構的學習

2.方法區保存什么?會被回收嗎?


方法區不是只保存的方法信息和代碼,同時在一塊叫做運行時常量池的子區域還

保存了Class文件中常量表中的各種符號引用,以及翻譯出來的直接引用。通過堆中

的一個Class對象作為接口來訪問這些信息。


雖然方法區中保存的是類型信息,但是也是會被回收的,只不過回收的條件比較苛刻:


(1)該類的所有實例都已經被回收


(2)加載該類的ClassLoader已經被回收


(3)該類的Class對象沒有在任何地方被引用(包括Class.forName反射訪問)



3.方法區中常量池的內容不變嗎?


方法區中的運行時常量池保存了Class文件中靜態常量池中的數據。除了存放這些編譯時

生成的各種字面量和符號引用外,還包含了翻譯出來的直接引用。但這不代表運行時常量池

就不會改變。比如運行時可以調用String的intern方法,將新的字符串常量放入池中。


    package com.cdai.jvm;

public class RuntimeConstantPool {  

    public static void main(String[] args) {  

        String s1 = new String("hello");  
        String s2 = new String("hello");  
        System.out.println("Before intern, s1 == s2: " + (s1 == s2));  

        s1 = s1.intern();  
        s2 = s2.intern();  
        System.out.println("After intern, s1 == s2: " + (s1 == s2));  

    }  

}  </pre><br />


4.所有的對象實例都在堆上分配嗎?


隨著逃逸分析技術的逐漸成熟,棧上分配、標量替換優化技術使得“所有對象都分配

在堆上”也變得不那么絕對。


所謂逃逸就是當一個對象的指針被多個方法或線程引用時,我們稱這個指針發生逃逸。

一般來說,Java對象是在堆里分配的,在棧中只保存了對象的指針。假設一個局部變量

在方法執行期間未發生逃逸(暴露給方法外),則直接在棧里分配,之后繼續在調用棧

里執行,方法執行結束后棧空間被回收,局部變量就也被回收了。這樣就減少了大量臨時

對象在堆中分配,提高了GC回收的效率。


另外,逃逸分析也會對未發生逃逸的局部變量進行鎖省略,將該變量上擁有的鎖省略掉。

啟用逃逸分析的方法時加上JVM啟動參數:-XX:+DoEscapeAnalysis?EscapeAnalysisTest。



5.訪問堆上的對象有幾種方式?


(1)指針直接訪問


棧上的引用保存的就是指向堆上對象的指針,一次就可以定位對象,訪問速度比較快。

但是當對象在堆中被移動時(垃圾回收時會經常移動各個對象),棧上的指針變量的值

也需要改變。目前JVM HotSpot采用的是這種方式。


關于JVM結構的學習


(2)句柄間接訪問


棧上的引用指向的是句柄池中的一個句柄,通過這個句柄中的值再訪問對象。因此句柄

就像二級指針,需要兩次定位才能訪問到對象,速度比直接指針定位要慢一些,但是當

對象在堆中的位置移動時,不需要改變棧上引用的值。


關于JVM結構的學習

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!