每天學習一點JVM之:JAVA記憶體區域淺析

LemonYang發表於2016-12-03

關於JVM系列的文章,都是在讀了《深入理解java虛擬機器》一書之後的讀書筆記總結。

對於很多android的初學者來說,JVM知識可能是相當薄弱的一塊知識。可是如果你需要到公司入職、你要提高自己駕馭java的能力,那麼JVM卻是絕對不可忽視的一個環節。最基本JAVA記憶體區域、垃圾回收機制和演算法、類載入等等都是必須掌握的內容。

接下來自己會寫一些自己的讀書筆記,跟大家一起共享一些比較簡單又應該掌握的JVM的知識(但是對於JVM的內部更深層次的知識不會去討論,因為自己在那些方面的知識真的只是皮毛,還要好好深入學習)。

首先,看圖說話(下圖是java虛擬機器執行時資料區圖):

每天學習一點JVM之:JAVA記憶體區域淺析

根據上圖,我們可以發現java虛擬機器執行時記憶體共劃分成了5個區,分別是:方法區(method area)、堆(heap)、虛擬機器棧(vm stack)、本地方法棧(native method stack)和程式計數器(program counter register).其中,方法區和堆屬於所有執行緒共享的記憶體區域。

程式計數器

從名字我們大概可以看到,這個其實是用來指示當前虛擬機器所執行的位元組碼所在的指令地址(對於native方法而言,這個記憶體的值是空)。

為了線上程切換的時候,能夠正確載入執行緒的執行位置,就需要根據這個計數器來指示,因此這個記憶體區是執行緒私有的,每個執行緒都會具有自己的程式計數器,互不影響。

java虛擬機器棧

虛擬機器棧(也就是我們通常論述的java堆疊中的“棧”),它描述的是java方法的執行的記憶體模型,它是一個棧,棧裡面的存放的元素我們稱之為棧幀。因此每個方法的生命週期其實就是棧幀的出棧和入棧道過程。棧幀的具體內容如下圖所示:

每天學習一點JVM之:JAVA記憶體區域淺析

由上圖我們可以發現棧幀裡面包含了區域性變數表、運算元棧、動態連線、返回地址以及其他的一些額外資訊等。其中,在程式編譯的時候,就已經確定了區域性變數表、和運算元棧的大小(棧幀佔用記憶體的大小在編譯的時候就已經確定)

  • 區域性變數表

    區域性變數表是一組變數值儲存空間,用於存放方法引數和方法內部定義的區域性變數。包括編譯期間可知的各種基本資料型別(boolean、byte、short、int、float、char、long、double,其中long和double使用了兩個區域性變數空間來表示)、物件引用型別(物件例項的引用(類似於指標),通過它可以能直接或者間接的查詢到物件在堆中資料存放的起始地址索引,並且能查詢到物件所屬型別在方法區中的儲存的型別資訊)和returnAddress型別。

    虛擬機器通過索引定位的方式使用區域性變數表,索引值的範圍是0-區域性變數表最大的slot(區域性變數表的最小容量單位,一個slot可以儲存除long和double以外的任意一個基本資料型別)數量。在執行例項方法(即非static限定的方法)的時候,區域性變數表的第0個slot預設是用於傳遞方法所屬物件的例項的引用(也就是我們使用的this物件),其餘引數則按照參數列順序排列。

  • 運算元棧

    一個方法剛開始執行的時候,運算元棧為空,在執行過程中,各種位元組碼指令會進行入棧和出棧的操作(比如算術運算的時候和方法呼叫的時候)。值得注意的是,運算元棧中的元素型別必須於位元組碼指令序列嚴格匹配。

本地方法棧

和java虛擬機器棧相類似,只是虛擬機器棧是為java虛擬機器執行java方法服務的,而本地方法棧是為虛擬機器使用native方法服務的。

堆是所有執行緒共享的一塊記憶體區域,在虛擬機器啟動的時候就被建立出來。這片記憶體區用於存放物件例項,幾乎所有的物件例項都在這裡分配記憶體。堆區是java虛擬機器垃圾收集器管理的主要區域。

方法區

方法區也是屬於執行緒共享的一塊記憶體區域,它用於儲存已被java虛擬機器載入的類資訊、常量、靜態變數、即使編譯器編譯後的程式碼等資料。

  • 執行時常量池

    方法區的一部分,用於存放編譯期生成的各種字面量和符號引用。

總體的內容大概就這麼多,如果你有其他想要了解的東西,歡迎評論一起學習。如果你喜歡這篇文章,歡迎點贊收藏,也歡迎你關注我,接下來自己都會利用下班時間寫一些自己的實踐經驗和學習分享。最後,感謝你寶貴的時間閱讀這篇文章!

相關文章