天天看點

深入了解JVM虛拟機讀書筆記——運作時資料區

跨平台性是 Java 語言的重要特性,而這一特性本質上就是通過 JVM 虛拟機來實作的。下面就來通過深入學習 JVM 來進一步增加我們對 Java 這門程式設計語言的了解吧!(個人建議,最好能買來這本書去讀一讀,是非常有幫助的,當然,在看這本書之前,為了友善了解相關概念名詞,可以先跟着某馬程式員的視訊課程大緻過一遍 JVM 的内容體系:JVM 虛拟機基礎入門視訊教程,視訊教程的全套筆記)

1. 運作時資料區

Java與C++之間有一堵由記憶體動态配置設定和垃圾收集技術所圍成的高牆,牆外面的人想進去,牆裡 面的人卻想出來 —— 摘自(深入了解 Java 虛拟)。

Java 虛拟機在執行 Java 程式的過程中會把它所管理的記憶體劃分為若幹個不同的資料區域。這些區域 有各自的用途,以及建立和銷毀的時間,有的區域随着虛拟機程序的啟動而一直存在,有些區域則是依賴使用者線程的啟動和結束而建立和銷毀。根據《Java虛拟機規範》的規定,Java虛拟機所管理的記憶體 将會包括以下幾個運作時資料區域,如下圖所示。

深入了解JVM虛拟機讀書筆記——運作時資料區
深入了解JVM虛拟機讀書筆記——運作時資料區

下面我們來逐個學習一下運作時資料區的 5 個部分。(注意:JVM 運作時資料區可不能等同于 JVM 記憶體模型,對于不太熟悉 JVM 的初學者,面試的時候很容易把這兩個概念搞混~)

1.1 程式計數器

程式計數器(線程私有),是一塊較小的記憶體空間,它可以看作是目前線程所執行的位元組碼的行号訓示器。它的核心作用就是:用于存儲下一條所要執行的 JVM 指令的記憶體位址。

這裡所說的線程私有,即不會出現并發安全問題,JVM 運作時資料區的 5 個部分中,隻有 Java 堆、方法區是線程共享的,其他三個均為線程私有,後面還會提到這個知識點。

如下圖:

深入了解JVM虛拟機讀書筆記——運作時資料區
深入了解JVM虛拟機讀書筆記——運作時資料區

Java指令執行流程:

每一條二進制位元組碼(JVM指令) 通過 解釋器 轉換成 機器碼 然後 就可以被 CPU 執行了!

當 解釋器 将一條jvm 指令轉換成 機器碼後 其會 向程式計數器 遞交 下一條 jvm 指令的執行位址!

程式計數器在硬體層面 其實是通過 寄存器 實作的!

是以程式計數器的作用就是:用于儲存JVM中下一條所要執行的指令的位址!

1.2 虛拟機棧

與程式計數器一樣,虛拟機棧也是線程私有的,它的生命周期與線程相同。虛拟機棧描述的是J ava 方法執行的線程記憶體模型:每個方法被執行的時候,Java虛拟機都會同步建立一個棧幀(Stack Frame),棧幀包含如下幾個組成部分:

局部變量表:存放基本資料類型(boolean、byte、char、short、int、 float、long、double)、對象引用(reference)等。這些資料類型在局部變量表中的存儲空間以局部變量槽(Slot)來表示,其中64位長度的 long 和 double 類型的資料會占用兩個變量槽,其餘的資料類型隻占用一個。局部變量表所需的記憶體空間在編譯期間完成配置設定,當進入一個方法時,這個方法需要在棧幀中配置設定多大的局部變量空間是完全确定的,在方法運作期間不會改變局部變量表的大小(這裡說的“大小”是指變量槽的數量)。

操作數棧:也可以稱之為表達式棧(Expression Stack),在方法執行過程中,根據位元組碼指令,往棧中寫入資料或提取資料,即入棧(push)和 出棧(pop)。某些位元組碼指令将值壓入操作數棧,其餘的位元組碼指令将操作數取出棧,使用它們後再把結果壓入棧,比如:執行複制、交換、求和等操作。操作數棧,主要用于儲存計算過程的中間結果,同時作為計算過程中變量臨時的存儲空間。

深入了解JVM虛拟機讀書筆記——運作時資料區
深入了解JVM虛拟機讀書筆記——運作時資料區

動态連接配接

方法出口等資訊

每個線程運作需要的記憶體空間,這一空間被稱為虛拟機棧(Frames),每一個方法被調用直至執行完畢的過程,就對應着一個棧幀在虛拟機棧中從入棧到出棧的過程。

每個棧由多個棧幀(Frame) 組成,對應着每個方法運作時所占用的記憶體,每個線程隻能有一個活動棧幀,對應着目前正在執行的方法,當方法執行時壓入棧,方法執行完畢後彈出棧。

深入了解JVM虛拟機讀書筆記——運作時資料區

1.3 本地方法棧

一些帶有native 關鍵字的方法就是需要JAVA去調用本地的C或者C++方法,因為JAVA有時候沒法直接和作業系統底層互動,是以需要用到本地方法!

如圖:

深入了解JVM虛拟機讀書筆記——運作時資料區

1.4 堆

堆是Java記憶體區域中一塊用來存放對象執行個體的區域【幾乎所有的對象執行個體都在這裡配置設定記憶體】,Java 堆(Java Heap)是 Java 虛拟機所管理的記憶體中最大的一塊 Java 堆是被所有線程共享的一塊記憶體區域。

Java堆既可以被實作成固定大小的,也可以是可擴充的,不過目前主流的Java虛拟機都是按照可擴充來實作的(通過參數-Xmx和-Xms設定)。如果在Java堆中沒有記憶體完成執行個體配置設定,并且堆也無法再擴充時,Java虛拟機将會抛出OutOfMemoryError異常。

記憶體中的對象都需要考慮線程安全問題。

Java 堆是垃圾收集器管理的主要區域,是以很多時候也被稱做“GC 堆”(Garbage)。

-Xmx -Xms:JVM初始配置設定的堆記憶體由-Xms指定,64位的作業系統上,堆大小預設是實體記憶體的1/64。

1.5 方法區

方法區(Method Area)與Java堆一樣,是各個線程共享的記憶體區域,它用于存儲已被虛拟機加載的類資訊、常量、靜态變量、即時編譯器編譯後的代碼緩存等資料。

方法區隻是一個抽象概念,其具體實作是通過以下 2 種方式:

永久代:JDK1.7版本之前。

元空間:JDK1.8版本之後。

永久代如下圖所示:

深入了解JVM虛拟機讀書筆記——運作時資料區
深入了解JVM虛拟機讀書筆記——運作時資料區

元空間如下圖所示:

深入了解JVM虛拟機讀書筆記——運作時資料區

由上圖可以看出,1.6版本方法區是由PermGen永久代實作(使用堆記憶體的一部分作為方法區),且由JVM 管理,由Class ClassLoader 常量池(包括StringTable) 組成。

1.8 版本後,方法區交給本地記憶體管理,而脫離了JVM,由元空間實作(元空間不再使用堆的記憶體,而是使用本地記憶體,即作業系統的記憶體),由Class ClassLoader 常量池(StringTable 被移到了Heap 堆中管理) 組成。

2. 面試題案例

JVM面試題案例

後續會陸續更新,這本書的筆記記的差不多了,排版和格式需要花時間整理,文章都會同步到公衆号上,也歡迎大家通過公衆号加入我的交流qun互相讨論jvm這塊的知識内容!