1. 程式人生 > >【深入理解Java虛擬機】自動內存管理機制——內存區域劃分

【深入理解Java虛擬機】自動內存管理機制——內存區域劃分

現在 深入 元素 原因 生成 內存泄漏 即時編譯器 內存劃分 責任

??Java與C++之間有一堵有內存動態分配和垃圾收集技術所圍成的“高墻”,墻外面的人想進去,墻裏面的人卻想出來。C/C++程序員既擁有每一個對象的所有權,同時也擔負著每一個對象生命從開始到終結的維護責任,而Java最大的優勢之一就是將內存控制的權力交給了Java虛擬機。在虛擬機自動內存管理機制的幫助下,程序員幾乎不用擔心內存泄漏和內存溢出的問題。

??然而,這裏說的僅僅是幾乎不會出現,特殊情況下,一旦出現了類似問題,程序員也需要對虛擬機的自動內存管理機制有所了解,才可能排查出相應的錯誤。


Java虛擬機內存區域劃分

??Java虛擬機在執行java程序的過程中,會把它所管理的內存劃分為幾個不同的數據區域,每個數據區域有各自的用途,有些隨虛擬機進程啟動而存在,有些隨用戶線程而存在。這些區域主要包括:程序計數器、Java虛擬機棧、本地方法棧、Java堆、方法區、直接內存


技術分享圖片

1. 程序計數器

??程序計數器是很小的一個空間,可以看做是當前線程所執行的字節碼的行號指示器,也就是用以決定下一條將要執行的字節碼指令,比如分支、循環、跳轉等語句都需要依賴PC來完成。

??由於多線程之間是通過時間片輪轉來占用CPU資源,所以每一個線程都有自己獨立的程序計數器,各線程獨立存儲,互不影響,因此,這一小塊內存是線程私有的。

??需要註意一點:如果線程執行的是java方法,那麽PC記錄的是正在執行的字節碼指令地址;而如果正在執行的是Native方法(本地方法,實現不是由java語言完成的),那麽PC值為空。

2. Java虛擬機棧

??虛擬機棧就是我們常說的內存中的棧空間,也是線程私有

的,生命周期與線程相同,是為字節碼(Java方法)服務的,用來支持java方法的執行

??虛擬機棧裏存放的元素是棧幀(用以存放局部變量表、操作棧、動態鏈接、方法返回值、附加信息等),每一個方法從調用直到執行完成,就對應著一個棧幀在虛擬機棧中從入棧到出棧的過程。java方法是基於棧的執行引擎,這裏的棧指的就是棧幀中的操作棧。

??棧幀的結構重點是局部變量表和操作棧,其余都屬於棧幀信息。需要註意的是,棧幀中需要多大的局部變量表,多大的操作棧,這些都是在編譯時就確定的,存在了方法表的Code屬性中,運行時不會改變。

??局部變量表用以存放方法的參數和內部定義的局部變量,基本單位是slot(變量槽,一般是32位),64位的long和double會占據兩個連續的slot。局部變量表的開頭存放的是參數

,對於實例方法,第0位索引的slot默認是this參數,後續依次是其他參數。參數表之後是內存定義的其他局部變量。

??操作棧是java方法執行所依賴的基本結構,各種字節碼指令都是通過向操作棧中寫入和提取內容來完成相應的運算或者調用其他的方法。所有的運算過程,都以操作棧的出棧和入棧作為信息交換的途徑

3. 本地方法棧

??本地方法棧和虛擬機棧是完全相同的,唯一的差別是本地方法棧是為native方法服務,有的虛擬機將這兩部分合二為一,有的分成兩部分實現,本質上沒有差別。

4. Java堆

??堆空間是虛擬機所管理內存中最大的一塊,所有的對象實例以及數組都在堆上分配(簡單理解就是一般所有new出來的都在堆空間中),由虛擬機啟動時創建,所有線程共享這一塊區域。

??Java堆不一定物理上連續,邏輯上連續即可。更重要的一點是,Java堆是垃圾收集器管理的主要區域,因此也被稱為“GC堆”。現在的垃圾收集器一般都采用分代收集算法,也就是為了更好對內存進行回收,進一步將堆空間劃分為:新生代和老年代。新生代更進一步可以劃分為:Eden空間、From Survivor空間和To Survivor空間。

5. 方法區

??方法區又稱為“永久代”,類似於堆空間,是所有線程共享的內存區域,用以存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯後的代碼等數據。

??方法區同樣可以不一定在物理上連續,這一塊區域可以實現垃圾收集,也可以不實現,或者直接將堆空間的垃圾收集機制擴展到方法區即可。原因是,這塊區域的回收目標主要是常量池的回收和對類型的卸載,這個區域很少情況下需要回收,這也是被稱為“永久代”的原因。

??方法區中很重要的一部分是運行時常量池,用於存放在編譯期生成的各種字面量和符號引用,在類加載完成後進入方法區的運行時常量池中存放。其中,字面量很好理解,比如文本字符串、聲明為final的常量值等,而符號引用主要指的是以下三類:類和接口的全限定名,字段的名稱和描述符,方法的名稱和描述符

6. 直接內存

??直接內存不是虛擬機運行時數據區的一部分,是jdk1.4以後引入的一種基於通道和緩沖區的I/O方式,可以使用native本地函數庫直接分配堆外內存。

【深入理解Java虛擬機】自動內存管理機制——內存區域劃分