【Java學習筆記】一張圖帶你入門JVM


進入公司不久,一同事問我,你知道怎麼查看JVM的內存溢出嗎?當時我就蒙了,怎麼查看呢?筆者之前一直使用的是 JProfiler去找的,但是真要說,筆者真說不出來。說起內存溢出,筆者發現筆者似乎對JVM都不太瞭解。之前雖然有寫《從HelloWorld看Class Loader》 ,但是對於整個JVM的內存體系還是不是瞭解的。所以筆者今天整理了下關於JVM這塊的相關內容。作爲入門級別的。首先自然是要了解下JVM的內存體系的。

一張圖走進JVM內存體系

大家先看這張圖:

這個是JVM裏面的一個整體的執行流,但我們這邊不討論ClassLoad,只看我們的 運行時數據區,看下面這張圖:
jvm_location

在JVM中,內存一般分成三大塊: 堆 , 方法區 , 棧。 我們可以根據這個分類來逐步分析JVM的內存體系。

JVM中的堆,我個人習慣性稱爲類實例區,這麼說就好理解了,也就是說這裏面放的是實例。也就是我們的Objects。可以說,幾乎所有的對象實例都在這裏分配內存空間。Java堆是垃圾收集器管理的主要區域,因此很多時候也被稱做“GC堆”。堆裏面一般分爲新生代和老年代。數組也是在這裏。

新生代

新生代,我之前看資料的時候,也有人稱爲年輕代,其實這個只是一個翻譯問題是吧。在我們的新生代裏面會分爲三個空間,分別是: Eden空間From Survivor 空間To Survivor空間。通常情況下,這個分配比例是8:1:1來的。

老年代

關於老年代,通俗的理解就是新創建的對象先進入新生代,新生代用完之後,沒用了,那就要進入老年代。所以說老年代屬於那種創建久而且還未被回收的對象的必然歸宿。俗話說得好,落葉歸根,魂歸故里。所以呢,早老年代一般都會提到他的GC算法,但我們今天只說這個內存結構,不閒聊。

我從網上到了一張圖,大家可以參考這張圖:

方法區

方法區(Method Area)與Java堆一樣,是各個線程共享的內存區域,它用於存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯後的代碼等數據。雖然Java虛擬機規範把方法區描述爲堆的一個邏輯部分,但是它卻有一個別名叫做Non-Heap(非堆),目的應該是與Java堆區分開來。

當然很多人願意稱方法區爲永久代。但是筆者也看到有人說這兩者存在着本質的區別。僅僅是因爲HotSpot虛擬機的設計團隊選擇把GC分代收集擴展至方法區,或者說使用永久代來實現方法區而已。

Java8 與元數據

在Java8中,永久代已經被移除,被一個稱爲“元數據區”(元空間)的區域所取代。元空間
的本質和永久代類似,元空間與永久代之間最大的區別在於:元空間並不在虛擬機中,而是使用本地內存。因此,默認情況下,元空間的大小僅受本地內存限制。類的元數據放入 native
memory, 字符串池和類的靜態變量放入 java 堆中,這樣可以加載多少類的元數據就不再由
MaxPermSize 控制, 而由系統的實際可用空間來控制。

程序計數器

這個區域不是用來計數的。但是作用和計數差不多。程序計數器是一塊很小的內存空間,它的作用可以認爲是當前線程執行的字節碼的行號的指示器。
此內存區域是唯一一個在Java虛擬機規範中沒有規定任何OutOfMemoryError情況的區域。
大家注意,每一個線程都會有自己的專屬的計數器,也就是說,這個是私有的,並不是共享的。同樣,如果程序執行的是 Native 方法,那這個計數器爲空,也就是 Undefined

JVM棧(JVM Stacks)

與程序計數器一樣,Java虛擬機棧(Java Virtual Machine Stacks)也是線程私有的,它的生命週期與線程相同。虛擬機棧描述的是Java方法執行的內存模型:每個方法被執行的時候都會同時創建一個棧幀(Stack Frame)用於存儲局部變量表、操作棧、動態鏈接、方法出口等信息。每一個方法被調用直至執行完成的過程,就對應着一個棧幀在虛擬機棧中從入棧到出棧的過程。

本地方法棧(Native Method Stacks)

本地方法棧則是爲虛擬機使用到的Native方法服務

總結

到這裏,JVM裏面的基本的內容,可以說是入門的基礎算是結束了,接下來要關心的問題就是這裏面的堆裏面的具體內容了,這裏面是線程共享區域,也是新生代老年代區域,那就伴隨着垃圾回收。下一篇文章會重點看看這裏面的算法,這塊筆者還需要找找資料。

對於本篇文章,筆者簡單的繪製一張圖,這張圖基本上可以幫助我們入門JVM的內存結構了。
一張圖入門JVM

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