VM的內存結構和各個內存區域的作用

       JVM的內存結構和各個內存區域的作用,對於理解Java內存機制、工作原理有着較大幫助。首先看一下《深入理解Java虛擬機(第二版)》給出的JVM內存結構圖:

                                        
1.JVM結構分析

程序計數器:

       當執行一條指令時,首先需要根據程序計數器(PC)中存放的指令地址,將指令由內存取到指令寄存器中,此過程稱爲“取指令”。與此同時,PC中的地址或自動加1或由轉移指針給出下一條指令的地址。此後經過分析指令,執行指令。完成第一條指令的執行,而後根據PC取出第二條指令的地址,如此循環,執行每一條指令。

       程序計數器是一塊較小的內存空間,它的作用是當前線程所執行的字節碼的行號指示器。在虛擬機的概念模型裏(僅是概念模型,各種虛擬機可能會通過一些更高效的方式去實現),字節碼解釋器工作時就是通過改變這個計數器的值來選取下一條需要執行的字節碼指令,分支、循環、跳轉、異常處理、線程恢復等基礎功能都需要依賴這個計數器來完成。每個線程都擁有一個屬於本線程的PC寄存器,當線程執行某個java方法時,PC寄存器的內容總是下一條被執行指令的”地址”,這裏的”地址”可以是一個本地指針,也可以是在方法字節碼中相對於該方法起始指令的偏移量。如果該線程正在執行一個本地方法,那麼PC寄存器的值是”Undefined”。

方法區

       方法區(Method Area)是用於存儲類結構信息的地方,包括常量池、靜態變量、構造函數等類型信息,類型信息是由類加載器在類加載時從類文件中提取出來的。方法區中的常量池,包含着一些常量和符號引用(加載類的連接階段中的解析過程會將符號引用轉換爲直接引用),方法區是線程共享的。

堆:

       堆(heap)是存儲java實例或者對象的地方,是GC的主要區域,同樣是線程共享的內存區域。堆的優勢是可以動態地分配內存大小,生存期也不必事先告訴編譯器,Java的垃圾收集器會自動收走這些不在實用的數據。堆的缺點是由於運行時要動態分配內存,存取速度慢。

虛擬機棧:

       虛擬機棧(Java Virtual Machine Stacks)和線程是緊密聯繫的,每創建一個線程時就會對應創建一個Java棧。其生命週期和線程相同,其由一系列幀組成,每個幀保存一個方法的局部變量、操作數棧、動態鏈接和返回地址。當我們每調用一個方法,都會創建一個棧幀,並壓棧。每一個方法從調用到最終返回結果的過程,就對應一個棧幀從入棧到出棧的過程。棧的優勢是存取速度比堆要快。棧的缺點是存在棧的數據大小和生存期必須是確定的,缺乏靈活性。

本地方法棧

      本地方法棧和虛擬機棧的作用相似,不過虛擬機棧是爲用戶服務的,而本地方法棧是爲Java底層(即jvm本身,jvm調用的native方法)方法服務的。

       這裏對虛擬機棧和本地方法棧的區別做進一步說明:本地方法棧(Native Method Stacks)與虛擬機棧所發揮的作用是非常相似的,其區別不過是虛擬機棧爲虛擬機執行Java方法(也就是字節碼)服務,而本地方法棧則是爲虛擬機使用到的Native方法服務。虛擬機規範中對本地方法棧中的方法使用的語言、使用方式與數據結構並沒有強制規定,因此具體的虛擬機可以自由實現它。甚至有的虛擬機(譬如Sun HotSpot虛擬機)直接就把本地方法棧和虛擬機棧合二爲一。與虛擬機棧一樣,本地方法棧區域也會拋出StackOverflowError和OutOfMemoryError異常。我們在進行理解時,同意記爲棧即可。
2.結合代碼作進一步說明

首先看代碼:

    public class MemoryStructureTest { // 運行時jvm會把該類的代碼放入方法區
        
        public static String str = "abc";// 此靜態變量存於方法區的常量池
        
        public static void main(String[] args) {
            String string = new String("abc");// “string”即變量名放入棧,"abc"即值放入堆
            System.out.println(string);
        }
    }

具體內存分配請看代碼註釋。關於jvm爲什麼要這樣分配,讀者在閱讀第一部分的關於堆棧的優勢和劣勢後,結果可想而知了。

特殊說明:

      基本類型,即定義是通過諸如int a = 3; long b = 255L;的形式來定義的,稱爲自動變量。自動變量存的是字面值,不是類的實例,即不是類的引用,這裏並沒有類的存在 。如int a = 3; 這裏的a是一個指向int類型的引用,指向3這個字面值。這些字面值的數據,由於大小可知,生存期可知(這些字面值固定定義在某個程序塊裏面,程序塊退出後,字段值就消失了),出於追求速度的原因,就直接存在於棧中。  
————————————————
版權聲明:本文爲CSDN博主「超級戰鬥王」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/m0_38075425/article/details/81632258

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章