java 虛擬機內存區域

*Java是一套體系,包括Java程序設計語言、class字節文件、Java虛擬機和Java API。程序設計語言就是語法,思想,語義等,class字節文件時java程序編譯後形成的可直接在java虛擬機中運算的文件,Java虛擬機是Java程序能夠運行的保障,Java API提供了各種各樣的功能接口。

Java是跨平臺的,因爲只要是該平臺上有Java虛擬機,那就可以運行Java程序,因爲真正運行Java程序的是Java虛擬機。

不僅僅是Java語言可以在Java虛擬機上運行,許多其他的計算機語言也可以,甚至一些傳統的語言,也衍生出了能夠在jvm上運行的Java虛擬機版本,足以見得Java 虛擬機的重要性。

在64位操作系統上運行,64位的Java虛擬機比32位的虛擬機多消耗10%~30%內存,運行速度幾乎也慢了15%左右,隨着發展,64位虛擬機是必然主流的。

class文件是二進制數據,只有JVM可以識別,JVM就根據識別到的內容去執行,Java代碼是不能訪問和操作底層的,所以這個“執行”就是調用本地方法,由本地方法去做。

Java虛擬機運行時管理的內存區域

 

程序計數器(Program Counter Register)  線程私有

前言:Native關鍵字是修飾方法(函數)的,被native修改的方法叫做本地方法,和平臺有關,可移植性不好,類似於abstract抽象一樣,只有方法名,沒有方法的具體實現,方法的實現通常是能夠訪問操作系統底層的計算機語言編寫的(C或者C++等等),因爲Java語言不能夠訪問操作系統底層,所以Java代碼可以調用非Java代碼來訪問操作系統底層(通過這個native方法)。

程序計數器是以塊很小的內存,作用是記錄下一條指令的地址,有點像PC寄存器,每個線程都有自己的一個程序計數器。多線程的時候,cpu是輪流切換運行線程,那麼程序計數器可以幫助自己的線程執行和切換恢復。如果線程正在執行的是Java代碼,那麼程序計數器記錄下一條指令地址,如果是native代碼,那麼記錄值爲空

Java虛擬機對這塊內存沒有規定任何OutOfMemoryError異常。

Java虛擬機棧  線程私有

生命週期和線程一樣,一個線程一個棧,線程的創建就包括棧的創建,線程結束,棧就銷燬。線程裏的方法就對應於棧中的一個棧幀。出棧入棧的動態過程就和這些程序的一樣(當助教的時候,已經詳細學過了)。

這個區域規定了兩種異常:1,當線程訪問的深度超過了棧的深度(棧大小),出界了,報異常StackoverFlowError;2,當棧動態擴展的時候,擴展需要的內存大小沒有找到的時候,就會報OutOfMemoryError異常。

虛擬機棧供Java代碼用。

本地方法棧

Native方法是本地方法,本地方法是有能夠訪問操作系統底層的語言寫的,那麼這個本地方法執行的時候也需要“棧幀”,所以有了本地方法棧。也有StackoverFlowError和OutOfMemoryError。

Java堆是虛擬機管理的內存中最大的,在虛擬機啓動時就創建,唯一目的就是存放對象(類的實例),幾乎所有的對象都放在堆中(用new 創建),所以堆是垃圾管理的重要針對對象。堆不要求在物理內存上是連續的,可以是間斷的,只要邏輯上是連續的就行,所以堆的大小是可以擴展的,如果堆已經沒有內存去存放實例了,又無法擴展了,就拋出異常OutOfMemoryError。

方法區

和堆類似,不要求物理內存上連續,可以擴展。用於存放代碼相關的信息(比如一個類的類名,訪問修飾符,常量池,類型,父類,實現的接口 等等)。也有OutOfMemoryError。

運行時常量池

運行時常量池是方法區的一部分(jdk1.8以後,常量池放在了堆中,是堆的一部分),用於存放常量的。也OutOfMemoryError。 常量池主要存兩大類數據:字面量和符號引用。字面量:就是有字母、數字、符號組成的值,只能爲右值,int a=8; 8就是字面量,String s=“hello” ,hello就是字面量。符號引用:Java代碼中,不就是類、接口、類的字段、類的方法這些嗎,給它們一個引用和描述符,存在常量池,通過這個引用,就可以掌握代碼的框架,然後找到相應的類-》字段或者方法,執行相應代碼。

直接內存

直接內存就是不歸虛擬機管理的內存,就是機器的內存中剩餘的內存。虛擬機可以使用native方法在直接內存中分配一塊內存,然後在堆中用一個對象引用指向這塊內存,就可以操作這塊內存了。

舉個例子---------對象訪問

Object o = new Object();  假設這句在一個方法中。

 

1、在方法中,這個方法就會有一個棧幀,棧幀會爲變量等初始化空間出來,包括對象的引用。Object o就是一個引用,存放在棧幀中,作爲reference類型,這個棧幀肯定是存放在Java虛擬機棧中的。

2、new Object(); 這句是創建了一個實例,在Java堆中分配一個空間,存放着這個對象,不僅包含這個對象的變量的初始化數據等,還包含能夠查找到Object類的相關信息的地址(就是方法區中存的內容的地址)。

3、此時,方法區還會存儲這個Object類的相關信息。

 

棧幀中的“引用”如何去找到對象數據 和 類的相關數據?主流方式有兩種:句柄 和 直接使用指針。

句柄:

Java堆中分配一塊內存,用於存儲句柄,這塊內存叫做句柄池。句柄池存放着對象實例數據和對象類型數據(就是前面講的“類的相關數據”,以後都叫 對象類型數據 了)的地址,而引用只是句柄的地址,一旦對象的地址變了,JVM只需要修改句柄的內容即可,不需要修改引用。

指針:

對象類型數據,還是通過句柄來,但是對象實例數據,就直接用指針,引用就是對象實例數據的地址,對象的內存地址一旦變了,那麼引用也得變。

句柄和直接指針 ,各有優劣。不過這兩種方式都非常符合java特性,就是一個類可以有多個實例對象,類信息就一個,存在方法區就行,但是實例對象可以有多個,存在堆中。

 

發佈了88 篇原創文章 · 獲贊 21 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章