深入理解Java Runtime Area Java運行時數據區

  • Java Runtime Area的分類
  • 從線程的角度理解Java Runtime Area
  • 從存儲內容理解Java Runtime Area
  • 方法區中究竟存儲了哪些信息?
  • 基本數據類型的成員變量放在jvm的哪塊內存區域里?

Java Runtime Area的分類

Java Runtime Area主要可以分為六部分 :

  • Program Counter (PC) Register 程序計數器
  • Java Virtual Machine Stacks Java虛擬機棧
  • Heap Memory Java堆
  • Method Area 方法區
  • Run-time Constant Pool 運行時常量池
  • Native Method Stacks 本地方法棧

具體的每個區域的內容和特點可以參考《深入理解Java虛擬機》,此書已經講的很詳細了。
下面我們對這幾個數據區域進行分類,分別從不同的視角來分析,加深我們的理解

從線程的角度理解Java Runtime Area

首先,我們從區域是否是線程私有的還是所有線程共享的來分類:

image.png

程序計數器 Java虛擬機棧 本地方法棧都是線程私有的

Java堆****方法區****運行時常量池都是所有線程共享的

進一步理解:

  • 對于線程私有的數據區域程序計數器 Java虛擬機棧 本地方法棧,他們的生存周期都是一致的,都是
    隨著線程開始,而進行初始化
    隨著線程結束而銷毀

  • 而對于線程共享的數據區域Java堆****方法區****運行時常量池,他們的生存周期都是一致的
    隨著JVM的啟動而分配內存
    隨著JVM的關閉而銷毀

從存儲內容理解Java Runtime Area

下面我們再根據不同區域所存儲的數據類型進行分類:
可以分為三類

  • 方法區和常量池存儲類的信息
  • 堆內存存儲對象信息
  • 程序計數器,Java虛擬機棧,本地方法棧存儲線程的信息

下圖很清楚的說明

image.png

The heap space holds object data, the method area holds class code, and the native area holds references to the code and object data.
堆存儲object的data,方法區存儲class的信息和code,native區域存儲指向class信息和code的引用和指向對象的data的引用

下面這個圖更詳細的指出了三個區域存儲的內容:

image.png

下面我們通過一個實際代碼的例子,來說明;

看下面這段代碼:

image.png

這段代碼編譯之后,就存儲成如下這個樣子:

image.png

易混淆的Java Runtime Area 的問題

下面我們會對關于Java 運行時數據區易混淆的問題進行釋疑

方法區中究竟存儲了哪些信息?

棧中存放了局部變量表等與方法有關的信息,但方法中還有指令代碼這一重要內容,它既沒有放在棧(Stack)中也沒放在堆(Heap)中,那它放在哪呢?
其實,方法區中除了包括你所說的“已加載的類的基本信息、常量、靜態變量等”外,還包括編譯器編譯后的代碼,而且這應該是方法區中主要的一部分,畢竟類中主要是方法和屬性,而類中的屬性,如果是實例域的話則新建對象后存儲在堆(Heap)中,靜態的話就如你所說存儲在方法區中,因此該區域中方法占主要部分,這應該是此運行時數據區稱為方法區的原因吧。

基本數據類型的成員變量放在jvm的哪塊內存區域里?

比如

class{
private int i;
}

有的朋友可能因為基本數據類型,就認為存儲在棧中。但其實是存儲在堆中的,因為這是屬于對象的信息,每個對象都擁有不同的實例變量,這些實例變量都存儲在堆中,不管是基本數據類型還是引用數據類型
ava虛擬機棧是線程私有的,生命周期跟線程相同,每個方法調用的時候都會創建一個棧幀用于存儲局部變量表,操作數棧,動態鏈接,方法出口等信息。每個方法調用的過程,就代表了一個棧幀在虛擬機棧中入棧到出棧的過程,當進入一個方法時,這個方法在棧中需要分配多大的內存都是完全確定的,方法運行時不會改變局部變量表的大小——《深入理解java虛擬機第二版》
很多java程序員一開始就被網上的一些教程所誤導:基本數據類型放在棧中,數組和類的實例放在堆中。 這個說法不準確,事實上,如上面的實例變量i,他是存放在java堆中。因為它不是靜態的變量,不會獨立于類的實例而存在,而該類實例化之后,放在堆中,當然也包含了它的屬性i。
如果在方法中定義了int i = 0;則在局部變量表創建了兩個對象:引用i和0。 這兩個對象都是線程私有(安全)的。 比如定義了int[] is = new int[10]. 定義了兩個對象,一個是is引用,放在局部變量表中,一個是長度為10的數組,放在堆中,這個數組,只能通過is來訪問,方法結束后出棧,is被銷毀,根據java的根搜索算法,判斷數組不可達,就將它銷毀了。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容