友快網

導航選單

一個Java類在執行時候, 變數是怎麼在JVM中分佈的呢?

JVM學習第三篇思考:一個

Java

類在Jvm記憶體中是怎麼存在的

又名:Java虛擬機器的記憶體模型(JMM)是什麼樣的。

透過前面兩篇文章的學習,我們知道了一個Java類的

生命週期

及類載入器。我們可以得到如下兩幅圖:

類生命週期:

點選載入圖片

父類委託機制:

點選載入圖片

思考:

點選載入圖片

我們編寫的類中的變數、方法、物件這些都需要記憶體存放的。那麼在執行時候這些資料在Java虛擬機器記憶體中是怎麼存放的呢?

本文目標:

凱哥(凱哥Java:kaigejava)希望透過本文學習,大家對Java虛擬機器執行時資料區域有更深的瞭解

我們寫的程式碼在JVM中是怎麼存在的?

1:我們現在看看總體Java執行時資料模型:

點選載入圖片

2:我們來看看下面這段程式碼,執行的時候,在JVM中資料存放:

點選載入圖片

上面程式碼很簡單,那麼對應的變數、物件等在記憶體中都是怎麼分配的呢?

2。1:方法區

注:在JDK1。8之後,方法區被元空間替換了。

方法區:用來存放的是類的資訊、常量、靜態變數等。該區域也是各個執行緒共享的記憶體區域。

根據Java虛擬機器規範中的規定,當方法去無法滿足記憶體分配的時候,會丟擲:OutOfMemoryError異常的。

根據上面的 定義,我們可以知道比如我們JvmDemo。class資訊、static string str=“

jvm

Demo”是在方法區存放的。

對應咱們程式碼,方法區存放的如下圖:

點選載入圖片

2。2:堆區

堆區是JVM所管理的記憶體中的最大的一塊區域。該區域是所有執行緒共享的一塊記憶體區域。該區域空間在虛擬機器啟動的時候就被建立了(-Xms的設定。後面凱哥(凱哥Java:kaigejava)也會詳細講解的)。

此區域的目的是存放物件例項的。幾乎所有的物件例項都是在這裡分配的。Java虛擬機器規範中是這麼描述的:所有的物件的例項以及陣列都要在堆上分配。

堆區是垃圾收集器管理的主要區域(後面凱哥(凱哥Java:kaigejava)也會詳細講解的)。

堆區空間,在物理上可以不是連續的記憶體空間,只要在邏輯上是連續的即可。如果堆沒有記憶體完成例項分配,並且堆也無法在擴充套件的時候,將會丟擲異常:OutOfMemoryError。這個大家很熟悉吧。

根據上面定義的,我們可以知道,上面程式碼中Son son = new Son; 這行程式碼建立的例項物件是存放在堆區的。

點選載入圖片

2。3:程式計數器

程式計數器的作用可以看做是當前執行緒所執行的位元組碼的行號指示器。位元組碼直譯器在工作的時候,時候透過改變計數器的值來選擇接下來要執行的位元組碼指令的。

同時我們都知道,當多執行緒的時候,Java虛擬機器是透過執行緒輪流切換分配處理器執行時間的方式來實現的。在任何一個確定的時刻一個處理器只會執行一條執行緒中的指令。因此,為了解決多個執行緒在切換後,能夠迅速恢復到切換前執行的位置,每個執行緒都需要有個獨立的程式計數器,各個執行緒直接的計數器互不影響,獨立儲存的。一般稱這類記憶體區域為:“執行緒私有”的記憶體。當執行緒正在執行的一個方法是Native的,這種情況下,計數器的值就是undefined了。這個區域也是Java虛擬機器記憶體區域中唯一一個沒有OOM的區域。

根據上面描述,我們可以知道,我們自己編寫的*。java檔案要想被執行,需要被編譯成*。class的位元組碼檔案。位元組碼檔案對應各種位元組碼指令。比如我們上面JvmDemo的位元組碼檔案:

點選載入圖片

從上面截圖,我們可以看到,行號是0,3,4,7,8這樣的。程式計數器就是記錄這些行號的

我們也可以使用idea的外掛,來檢視我們JvmDemo的相關資訊:

點選載入圖片

2。4:虛擬機器棧

Java虛擬機器棧,也是執行緒私有的。其生命週期與執行緒相同,當一個執行緒執行結束後,對應的虛擬機器棧也結束。

虛擬機器棧是Java方法執行的記憶體模型:即每個方法被執行的時候,都會被同時建立一個棧幀(Stack Frame),這個棧幀是用來存放方法區域性變量表、操作棧、動態連結、方法出口等資訊。每一個方法被呼叫直到其執行完成的過程,就對應著一個棧幀在虛擬機器棧中入棧和出棧的過程。

比如:我們上面程式碼執行的時候,執行main方法的時候,主執行緒就會把main方法壓入到虛擬機器棧中,當執行到add方法的時候,add方法就被壓入到棧中了。當執行完add方法後,add方法就被從虛擬機器棧中彈出,這個時候add對應的棧幀也銷燬。

虛擬機器棧幀如下圖:

點選載入圖片

區域性變數存放:各種基本資料型別、物件引用和返回型別

八大基本資料型別:boolean、byte、char、short、init、float、long、double;

物件引用:reference型別。這裡是存放的是物件在對記憶體中的地址值。不等同於物件自身的。根據不同的虛擬機器的實現,這個指向可能是指向了物件起始地址的引用指標,也有可能是指向了物件物件的控制代碼或其他物件與其他物件的位置;

返回型別:returnAddress型別。指向一條位元組碼指令地址。

擴充套件:long型別和double型別的資料會佔用2個區域性變數空間。其他6個數據型別佔用1個。

區域性變量表所消耗的記憶體空間在編譯期間就完成了分配,當進入一個方法的時候,這個方法需要在棧幀中分配多大的區域性變數空間是完全確定的。在方法的執行期間,不會改變該區域空間大小的。

在咱們上面程式碼中,虛擬機器棧存放的就是咱們main方法和add方法相關的

2。5:本地方法棧

本地方法棧的作用和虛擬機器棧的作用相似。不同之處在於:虛擬機器棧是為了虛擬機器執行Java方法服務的。而本地方法棧則是為了虛擬機器使用到Native方法服務的。此區域也是方法私有的。比如我們呼叫執行緒的run方法或者CAS的時候,呼叫的都是native方法。

總結:

透過本文學習,我們在自己腦海中應該有如下圖的概念:

點選載入圖片

其中方法區、堆區是所有執行緒共享的;虛擬機器棧、程式計數器、本地方法棧這三個是執行緒私有的,其生命週期同線程一致。

方法區:存放型別、常量、靜態變數等

堆區:用來存放物件例項、陣列

虛擬機器棧:區域性變量表、動態連結、操作棧等

本地方法棧:用來存放當執行緒呼叫native方法的時候使用的

程式計數器:用來記錄當前執行緒執行的位元組碼行號的。

好了,本文凱哥(凱哥Java:kaigejava)就和大家嘮嘮在執行時候Java虛擬機器的資料區域。在下篇文章中,咱們在詳細嘮嘮堆區。

上一篇:盤點那些有趣的冷知識(六)一起來漲知識吧
下一篇:鬥魚一哥「旭旭寶寶」正式宣佈停播! 自爆: 與鬥魚合同已到期