1. 程式人生 > >詳解Java內存區域?虛擬機類加載機制?

詳解Java內存區域?虛擬機類加載機制?

div 次數 運行時數據區域 比較 入棧 image 基本數據類型 int 便是

一、Java運行時數據區域

1、程序計數器

“線程私有”的內存,是一個較小的內存空間,它可以看做當前線程所執行的字節碼的行號指示器。Java虛擬機規範中唯一一個沒有OutOfMemoryError情況的區域。

字節碼解釋器工作時就說通過改變這個計數器的值來選取下一條需要執行的字節碼指令,分支、循環、跳轉、異常處理、線程恢復等基礎功能都需要依賴這個計數器來完成。

技術分享圖片

2、Java堆(Java Heap)

Java堆是Java虛擬機所管理的內存中最大的一塊。在虛擬機啟動時創建,此內存區域的唯一目的就是存放對象實例,幾乎所有的對象實例都在這裏分配內存。
Java堆是垃圾收集器管理的主要區域,因此也稱為“GC堆”,如果在堆中沒有內存完成實例分配,並且堆也無法擴展時,將會拋出OutOfMemoryError異常。

3、本地方法棧

本地方法棧作用與虛擬機棧相似,區別在於虛擬機棧為虛擬機執行java方法服務,而本地方法棧則為虛擬機使用到的Native方法服務,線程私有。
Native方法常用的兩種請求:
①在方法中用java語言直接操作計算機硬件;

②在方法中調用一些不是有java語言寫的代碼;

4、Java虛擬機棧

Java 虛擬棧,線程私有的,它的生命周期與線程相同。每個方法在執行的同時都會創建一個棧幀用於存儲局部變量表、操作數棧、動態鏈接、方法出口等信息。通過人們所說的“棧”就說虛擬機棧,或說是虛擬機棧中的局部變量表部分。局部變量表存放了編譯期可知的各種基本數據類型,對象引用和returnAddress類型。操作數棧和局部變量表在訪問方式上存在著較大差異,操作數棧並非采用訪問索引的方式來進行數據訪問的,而是通過標準的入棧和出棧操作來完成一次數據訪問。每一個操作數棧都會擁有一個明確的棧深度用於存儲數值,當然操作數棧所需的容量大小在編譯期就可以被完全確定下來,並保存在方法的Code屬性中。

技術分享圖片

5、方法區

方法區用於存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯後的代碼等數據。當方法區無法滿足內存分配需求時,將拋出OutOfMemoryError異常。

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

運行時常量池相對於Class文件常量池的另外一個特征是具備動態性,Java語言並不要求常量一定只有編譯期才能產生,也就是並非預置入Class文件中常量池的內容才能進入方法區運行時常量池,運行期間也可能將新的常量放入池中,這種特性被開發人員利用的比較多的便是String類的intern方法。

二、對象的內存布局

技術分享圖片



技術分享圖片

三、對象的訪問定位

建立對象是為了使用對象,我們的Java程序需要通過棧上的reference數據來操作堆上的具體對象。目前主流的訪問方式有使用句柄和直接指針兩種。

1、如果使用句柄訪問的話,那麽Java堆中將會劃出一塊內存來作為句柄池,reference中存儲的就是對象的句柄地址,而句柄中包含了對象實例數據與類型各自的具體地址信息。

技術分享圖片

2、如果通過直接指針訪問,那麽Java堆對象的布局中就必須考慮如何放置訪問類型數據的相關信息,而reference中存儲的直接就是對象的地址。

技術分享圖片

四、對象的創建

技術分享圖片

五、類加載器

類加載器是類加載過程中加載階段中“通過一個類的全限定名來獲取描述此類的二加載字節流”的加載動作。主要分為啟動類加載器、擴展類加載器、應用程序類加載器,後面兩類加載器由Java語言實現,獨立於虛擬機外部,並全部繼承自抽象類java.lang.Loader。其加載順序的實現如下圖所示:

技術分享圖片

六、虛擬機類的加載機制

(一)、類加載的時機

1、類的生命周期:類從被加載到虛擬機內存中開始,到卸載出內存為止。

技術分享圖片

上圖中,加載、驗證、準備、初始化和卸載這五個階段的順序是確定的,類的加載過程必須按照這種順序按部就班的開始,而解析階段則不一定。

2、需立即對類進行“初始化”(而加載、驗證、準備自然需要在此之前開始)的有且只有的5種請求:

技術分享圖片

(二)、類加載的過程

類加載的全過程:加載、驗證、準備、解析和初始化這五個階段。

技術分享圖片

詳解Java內存區域?虛擬機類加載機制?