深入理解Java虛擬機——JVM的內存結構和內存分配策略

一、JVM內存模型
Java虛擬機在執行Java程序的過程中會把它所管理的內存劃分爲若干個不同的數據區域。這些區域都有各自的用途,以及創建和銷燬的時間,有的區域隨着虛擬機進程的啓動而存在,有些區域則依賴用戶線程的啓動和結束而建立和銷燬。根據《Java虛擬機規範(JavaSE 7版)》的規定,Java虛擬機所管理的內存將會包括以下幾個運行時數據區域:

1、程序計數器
程序計數器(Program Counter Register)是一塊較小的內存空間,可以看作是當前線程所執行的字節碼的行號指示器。在虛擬機的概念模型裏(僅是概念模型,各種虛擬機可能會通過一些更高效的方式去實現),字節碼解釋器工作時就是通過改變這個計數器的值來選取下一條需要執行的字節碼指令,分支、循環、跳轉、異常處理、線程恢復等基礎功能都需要依賴這個計數器來完成。

2、Java虛擬機棧
Java虛擬機棧(Java Virtual Machine Stacks)也是線程私有的,它的生命週期與線程相同。虛擬機棧描述的是Java方法執行的內存模型:每個方法在執行的同時都會創建一個棧幀(Stack Frame [1] )用於存儲局部變量表、操作數棧、動態鏈接、方法出口等信息。每一個方法從調用直至執行完成的過程,就對應着一個棧幀在虛擬機棧中入棧到出棧的過程。

3、本地方法棧
本地方法棧(Native Method Stack)與虛擬機棧所發揮的作用是非常相似的,它們之間的區別不過是虛擬機棧爲虛擬機執行Java方法(也就是字節碼)服務,而本地方法棧則爲虛擬機使用到的Native方法服務。在虛擬機規範中對本地方法棧中方法使用的語言、使用方式與數據結構並沒有強制規定,因此具體的虛擬機可以自由實現它。甚至有的虛擬機(譬如Sun HotSpot虛擬機)直接就把本地方法棧和虛擬機棧合二爲一。與虛擬機棧一樣,本地方法棧區域也會拋出StackOverflowError和OutOfMemoryError異常。

4、Java堆
Java堆(Java Heap)是Java虛擬機所管理的內存中最大的一塊。Java堆是被所有線程共享的一塊內存區域,在虛擬機啓動時創建。此內存區域的唯一目的就是存放對象實例,幾乎所有的對象實例都在這裏分配內存Java堆是垃圾收集器管理的主要區域,因此很多時候也被稱做“GC堆”(Garbage Collected Heap,幸好國內沒翻譯成“垃圾堆”)。從內存回收的角度來看,由於現在收集器基本都採用分代收集算法,所Java堆中還可以細分爲:新生代和老年代;再細緻一點的有Eden空間、From Survivor空間、To Survivor空間等。

5、方法區
方法區是靜態分配的,編譯器將變量綁定在某個存儲位置上,而且這些綁定不會在運行時改變。常數池,源代碼中的命名常量、String 常量和static 變量保存在方法區。

6、運行時常量池
運行時常量池(Runtime Constant Pool)是方法區的一部分。Class文件中除了有類的版本、字段、方法、接口等描述信息外,還有一項信息是常量池(Constant Pool Table),用於存放編譯期生成的各種字面量和符號引用,這部分內容將在類加載後進入方法區的運行時常量池中存放。

7、直接內存
直接內存(Direct Memory)並不是虛擬機運行時數據區的一部分,也不是Java虛擬機規範中定義的內存區域。但是這部分內存也被頻繁地使用,而且也可能導致OutOfMemoryError異常出現,所以我們放到這裏一起講解。

二、JVM內存分配
1、基礎數據類型直接在棧空間分配;

2、方法的形式參數,直接在棧空間分配,當方法調用完成後從棧空間回收;

3、引用數據類型,需要用 new 來創建,既在棧空間分配一個地址空間,又在堆空間分配對象的類變量;

4、方法的引用參數,在棧空間分配一個地址空間,並指向堆空間的對象區,當方法調用完後從棧空間回收;

5、局部變量 new 出來時,在棧空間和堆空間中分配空間,當局部變量生命週期結束後,棧空間立刻被回收,堆空間區域等待 GC 回收;

6、方法調用時傳入的實際參數,先在棧空間分配,在方法調用完成後從棧空間釋放;

7、字符串常量在 DATA 區域分配 ,this 在堆空間分配;

8、數組既在棧空間分配數組名稱, 又在堆空間分配數組實際的大小!

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