JVM基礎入門

2022-09-07 17:27:09 字數 3556 閱讀 2271

jvm(j**a virtual machine)為j**a虛擬機器,是執行在作業系統之上,為j**a程式提供支援。

負責載入class檔案,class檔案在檔案開頭有特定的檔案標示,將class檔案位元組碼內容載入到記憶體中,並將這些內容轉換成方法區中執行時資料結構並且classloader只負責class檔案的載入,至於它是否可以執行,則由execution engine決定

類載入器分為兩大類:

使用者自定義載入器:j**a.lang.classloader的子類,使用者可以定製類的載入方式

雙親委派機制:

當乙個類收到了類載入請求,他首先不會嘗試自己去載入這個類,而是把這個請求委派給父類去完成,每乙個層次類載入器都是如此,因此所有的載入請求都應該傳送到啟動類載入其中,只有當父類載入器反饋自己無法完成這個請求的時候(在它的載入路徑下沒有找到所需載入的class),子類載入器才會嘗試自己去載入。

執行引擎負責解釋命令,提交作業系統執行。

本地介面的作用是融合不同的程式語言為 j**a 所用,它的初衷是融合 c/c++程式,j**a 誕生的時候是 c/c++橫行的時候,要想立足,必須有呼叫 c/c++程式,於是就在記憶體中專門開闢了一塊區域處理標記為native的**,它的具體做法是 native method stack中登記 native方法,在execution engine 執行時載入native libraies。 目前該方法使用的越來越少了,除非是與硬體有關的應用,比如通過j**a程式驅動印表機或者j**a系統管理生產裝置,在企業級應用中已經比較少見。因為現在的異構領域間的通訊很發達,比如可以使用 socket通訊,也可以使用web service等等,不多做介紹。

每個執行緒都有乙個程式計數器,是執行緒私有的,就是乙個指標,指向方法區中的方法位元組碼(用來儲存指向下一條指令的位址,也即將要執行的指令**),由執行引擎讀取下一條指令,是乙個非常小的記憶體空間,幾乎可以忽略不記。這塊記憶體區域很小,它是當前執行緒所執行的位元組碼的行號指示器,位元組碼直譯器通過改變這個計數器的值來選取下一條需要執行的位元組碼指令。如果執行的是乙個native方法,那這個計數器是空的。用以完成分支、迴圈、跳轉、異常處理、執行緒恢復等基礎功能。不會發生記憶體溢位(outofmemory=oom)錯誤

供各執行緒共享的執行時記憶體區域。它儲存了每乙個類的結構資訊,例如執行時常量池(runtime constant pool)、欄位和方法資料、建構函式和普通方法的位元組碼內容。上面講的是規範,在不同虛擬機器裡頭實現是不一樣的,最典型的就是永久代(permgen space)和元空間(metaspace),但是例項變數存在堆記憶體中,和方法區無關

棧有分為j**a棧和本地方法棧,j**a棧是執行j**a方法服務,而本地方法棧則為虛擬機器使用到的native方法服務。

乙個jvm例項只存在乙個堆記憶體,堆記憶體的大小是可以調節的。類載入器讀取了類檔案後,需要把類、方法、常變數放到堆記憶體中,儲存所有引用型別的真實資訊,以方便執行器執行。

堆記憶體分為三部分:

在j**a7之前,堆記憶體邏輯上分為三部分:新生,養老,永久

新生區是類的誕生、成長、消亡的區域,乙個類在這裡產生,應用,最後被垃圾**器收集,結束生命。新生區又分為兩部分: 伊甸區(eden space)和倖存者區(survivor pace) ,所有的類都是在伊甸區被new出來的。倖存區有兩個: 0區(survivor 0 space)和1區(survivor 1 space)。當伊甸園的空間用完時,程式又需要建立物件,jvm的垃圾**器將對伊甸園區進行垃圾**(minor gc),將伊甸園區中的不再被其他物件所引用的物件進行銷毀。然後將伊甸園中的剩餘物件移動到倖存 0區。若倖存 0區也滿了,再對該區進行垃圾**,然後移動到 1 區。那如果1 區也滿了呢?再移動到養老區。若養老區也滿了,那麼這個時候將產生majorgc(fullgc),進行養老區的記憶體清理。若養老區執行了full gc之後發現依然無法進行物件的儲存,就會產生oom異常「outofmemoryerror」。

如果出現j**a.lang.outofmemoryerror: j**a heap space異常,說明j**a虛擬機器的堆記憶體不夠。原因有二:

(1)j**a虛擬機器的堆記憶體設定不夠,可以通過引數-xms、-xmx來調整。

(2)**中建立了大量大物件,並且長時間不能被垃圾收集器收集(存在被引用)。

minorgc的過程(複製->清空->互換)

1:eden、survivorfrom 複製到 survivorto,年齡+1

首先,當eden區滿的時候會觸發第一次gc,把還活著的物件拷貝到survivorfrom區,當eden區再次觸發gc的時候會掃瞄eden區和from區域,對這兩個區域進行垃圾**,經過這次**後還存活的物件,則直接複製到to區域(如果有物件的年齡已經達到了老年的標準,則賦值到老年代區),同時把這些物件的年齡+1

2:清空 eden、survivorfrom

然後,清空eden和survivorfrom中的物件,也即複製之後有交換,誰空誰是to

3:survivorto和 survivorfrom 互換

最後,survivorto和survivorfrom互換,原survivorto成為下一次gc時的survivorfrom區。部分物件會在from和to區域中複製來複製去,如此交換15次(由jvm引數maxtenuringthreshold決定,這個引數預設是15),最終如果還是存活,就存入到老年代

實際而言,方法區(method area)和堆一樣,是各個執行緒共享的記憶體區域,它用於儲存虛擬機器載入的:類資訊+普通常量+靜態常量+編譯器編譯後的**等等,雖然jvm規範將方法區描述為堆的乙個邏輯部分,但它卻還有乙個別名叫做non-heap(非堆),目的就是要和堆分開。對於hotspot虛擬機器,很多開發者習慣將方法區稱之為「永久代(parmanent gen)」 ,但嚴格本質上說兩者不同,或者說使用永久代來實現方法區而已,永久代是方法區(相當於是乙個介面inte***ce)的乙個實現,jdk1.7的版本中,已經將原本放在永久代的字串常量池移走。

永久儲存區(j**a7之前)是乙個常駐記憶體區域,用於存放jdk自身所攜帶的 class,inte***ce 的元資料,也就是說它儲存的是執行環境必須的類資訊,被裝載進此區域的資料是不會被垃圾**器**掉的,關閉 jvm 才會釋放此區域所占用的記憶體。

在j**a8中,永久代已經被移除,被乙個稱為元空間的區域所取代。元空間的本質和永久代類似。

元空間與永久代之間最大的區別在於:永久帶使用的jvm的堆記憶體,但是j**a8以後的元空間並不在虛擬機器中而是使用本機物理記憶體

因此,預設情況下,元空間的大小僅受本地記憶體限制。類的元資料放入 native memory, 字串池和類的靜態變數放入 j**a 堆中,這樣可以載入多少類的元資料就不再由maxpermsize 控制, 而由系統的實際可用空間來控制。

一 JVM基礎入門

jvm是執行在作業系統之上的,它與硬體沒有直接的互動 jvm是跨語言的平台,jvm與j a無關,任何語言只要其編譯結果滿足幷包含j a虛擬機器的內部指令集 符號表以及其他的輔助資訊,符合class檔案格式,它就是乙個有效的位元組碼檔案,就能夠被虛擬機器所識別並裝載執行。虛擬機器j a虛擬機器 特點 ...

jvm基礎引數

初始化堆記憶體大小,相當於 xx initheapsize 預設為系統記憶體的1 64 最大堆記憶體,相當於 xx maxheapsize,預設為系統的1 4 棧空間 xx threadstacksize,windows取決於記憶體大小,而其他系統預設為1024k 新生代大小 元空間,使用直接記憶體...

JVM基礎學習(一) JVM記憶體模型

在j a高階知識的學習中,jvm都是避不過去的一關,我個人對於jvm的理解其實就是相當於在作業系統的外層再加了一層中間層,從來遮蔽了具體硬體之間的不同實現,使得j a實現了最重要的特性 一次編譯,處處執行。本分類中的內容都是基於 深入理解j a虛擬機器 中的內容以及網路上面部落格整理,外加自己的理解...