淺談JVM內存結構

淺談JVM內存結構

(一)簡述

Java虛擬機在執行Java程序的過程中會把它所管理的內存劃分爲若干個不同的數據區域。這些區域都有各自的用戶,以及創建和銷燬的時間,有的區域隨着虛擬機進程的啓動而存在,有些區域則依賴用戶線程的啓動和結束而創建和銷燬。我們先來看一下JVM的內存分區:

在這裏插入圖片描述

PS:JDK 1.8 同 JDK 1.7 比,最大的差別就是:元數據區取代了永久代。元數據區的本質和永久代類似,都是對 JVM 規範中對方法區的實現。不過元數據區與永久代之間最大的區別在於:元數據空間並不在虛擬機中,而是使用本地內存。

(二)程序計數器

程序計數器是一塊較小的內存空間,它可以看作是當前線程執行的字節碼的行號指示器。
在虛擬機的概念模型,字節碼解釋器工作時,就是通過改變這個計數器的值來選取下一條需要執行的字節碼指令。

每條線程都有一個獨立的程序計數器。爲了線程切換後能恢復到正確的執行位置。java虛擬機的多線程是通過線程輪流切換並分配處理器執行時間的方式實現的,一個處理器(對於多核處理器來說就是一個內核)都只會執行一條線程中的指令。在多線程情況下,程序計數器記錄的是當前線程執行的位置,從而當線程切換回來時,就知道上次線程執行到哪了。

(三)本地方法棧

本地方法棧是爲 JVM 運行 Native 方法準備的空間,由於很多 Native 方法都是用 C 語言實現的,所以它通常又叫 C 棧。它與 Java 虛擬機棧實現的功能類似,只不過本地方法棧是描述本地方法運行過程的內存模型。本地方法被執行時,在本地方法棧也會創建一塊棧幀,用於存放該方法的局部變量表、操作數棧、動態鏈接、方法出口信息等。

(四)java虛擬機棧

Java虛擬機棧是描述Java方法運行過程的內存模型。Java 虛擬機棧會爲每一個即將運行的 Java 方法創建一塊叫做“棧幀”的區域,用於存儲局部變量表、操作數棧、動態鏈接、方法出口等信息。一個方法對應一個棧幀。局部變量表存放了各種基本類型、對象引用和returnAddress類型(指向了一條字節碼指令地址)。其中64位長度long和double佔兩個局部變量空間,其他只佔一個。

在這裏插入圖片描述

當方法運行過程中需要創建局部變量時,就將局部變量的值存入棧幀中的局部變量表中。Java 虛擬機棧的棧頂的棧幀是當前正在執行的活動棧,也就是當前正在執行的方法,PC 寄存器也會指向這個地址。只有這個活動的棧幀的本地變量可以被操作數棧使用,當在這個棧幀中調用另一個方法,與之對應的棧幀又會被創建,新創建的棧幀壓入棧頂,變爲當前的活動棧幀。方法結束後,當前棧幀被移出,棧幀的返回值變成新的活動棧幀中操作數棧的一個操作數。如果沒有返回值,那麼新的活動棧幀中操作數棧的操作數沒有變化。

由於Java虛擬機棧是與線程對應的,數據不是線程共享的,因此不用關心數據一致性問題,也不會存在同步鎖的問題。

Java虛擬機棧規定的異常情況有兩種:
1.線程請求的棧的深度大於虛擬機所允許的深度,將拋出StackOverflowError異常;
2.如果虛擬機可以動態擴展,如果擴展時無法申請到足夠的內存,就拋出OutOfMemoryError異常。

(五)堆

Java堆(Java Heap)是Java虛擬機所管理的內存中最大的一塊。Java堆是所有線程共享的一塊內存區域,在虛擬機啓動時創建。

java堆的唯一目的就是存放對象實例對象。幾乎所有的對象實例都在這裏分配。這一點在java虛擬機規範中描述:所有的對象實例以及數組都要在堆上分配,但隨着JIT編譯器的發展與逃逸分析技術的成熟,所有的對象都分配在堆上也變的不是那樣“絕對”了。

java堆是垃圾收集器管理的主要區域,因此很多地方也稱爲“GC堆”,從內存回收角度看,由於現在收集器基本都採用分代收集算法,java堆中還可以細分:新生代、老年代。新生代再細分可分爲Eden空間、From Survivor空間、To Survivor空間。

當前主流的虛擬機的堆空間都是按照可擴展來實現的,通過(-Xmx和-Xms控制)。堆無法擴展時,拋出OutOfMemoryError異常。

(六)元數據區

在jdk1.8中,JVM移除了永久代,取而代之的是元數據區,也稱爲元空間(Metaspace) ,也就是將本地內存用來存儲,容量取決於是32位或是64位操作系統的可用內存大小。元數據區是方法區的一種實現,這時候字符串常量池還在堆, 運行時常量池還在方法區, 只不過方法區的實現從永久代變成了元空間。當方法區無法滿足內存分配需求時,拋出OutOfMemoryError異常。

元數據區是線程共享的。 整個虛擬機中只有一個元數據區。元數據區中的信息一般需要長期存在,回收一遍之後可能只有少量信息無效。因此內存回收效率低。主要回收目標是:對常量池的回收、對類型的卸載。Java虛擬機規範對方法區的要求比較寬鬆,和堆一樣,允許固定大小,也允許動態擴展,還允許不實現垃圾回收。

2020年6月1日

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