首頁>Club>
java面試中常問的JVM知識點彙總
2
回覆列表
  • 1 # 此生唯一

    一,JVM記憶體結構:在JVM記憶體結構中,大致(為什麼是大致?因為虛擬機器的種類繁多,有些虛擬機器把棧概念合二為一,還有其他自由的實現)會分為如下的結構:

    包括本地方法棧,VM棧,程式計數器,方法區,java堆,下面逐一來看下他們的功能:

    ①本地方法棧:放著大量虛擬機器可直接呼叫的native方法,比如CAS模型中大量使用的Unsafe包中的方法,基本都是native方法,這些方法很多並不是用java實現的,而是C,C++等;但是可供java直接呼叫;

    ②,vm棧:存放執行緒執行方法時產生的棧幀,通常一個執行緒會有一個棧幀鏈,如下圖所示,一個執行緒正在執行的棧幀只會是一個當前棧幀,棧幀中包含的資料結構包括:區域性變量表(方法中的區域性變數)、運算元棧(運算過程中的中間儲存媒介)、動態連結、方法返回地址和一些額外的附加資訊,如下圖:

    ④,方法區:存放已經被虛擬機器載入的類資訊,常量,靜態變數,即時編譯器編譯後的程式碼等資料,還有執行時常量,通常稱為永久代,通常情況不會進行GC;

    ⑤,java堆:絕大多數例項物件都在此存放;

    換個圖來看java記憶體模型可知:方法區和堆是執行緒共享的,其他的區域是執行緒私有的;

    二,JVM GC:

    1),物件是否能回收的判斷:

    (1),不可達性物件可以回收;

    (2),對於用可達性分析法搜尋不到的物件,GC並不一定會回收該物件。要完全回收一個物件,至少需要經過兩次標記的過程:

    第一次標記:對於一個沒有其他引用的物件,篩選該物件是否有必要執行finalize()方法,如果沒有執行必要,則意味可直接回收。(篩選依據:是否複寫或執行過finalize()方法;因為finalize方法只能被執行一次)。

    第二次標記:如果被篩選判定位有必要執行,則會放入FQueue佇列,並自動建立一個低優先順序的finalize執行緒來執行釋放操作。如果在一個物件釋放前被其他物件引用,則該物件會被移除FQueue佇列。

    根搜尋演算法:JVM選定諸如方法區的靜態常量,本地方法中的物件等作為GC roots(物件可達樹的根節點),將建立的所有的物件引用掛在樹上,當物件引用從樹上解掛時(沒有物件再引用這個物件時),則這個物件處於不可達狀態,也即是可回收狀態;如下圖:

    2)JVM記憶體分割槽和GC演算法

    記憶體被切分為三塊:新生代(剛new出來的物件),老年代(從新生代GC過來的物件或者剛new出來的大物件(直接超過了新生代的空閒記憶體)),永久代(方法區資料)

    新生代又被分為一塊Eden區和兩塊Survivor區;

    新生代GC演算法:複製演算法採用的方式為從根集合進行掃描,將存活的物件移動到一塊空閒的區域

    標記-清除:該演算法採用的方式是從跟集合開始掃描,對存活的物件進行標記,標記完畢後,再掃描整個空間中未被標記的物件,並進行清除。標記和清除的過程如下:

    上圖中藍色部分是有被引用的物件,褐色部分是沒有被引用的物件。在Marking階段,需要進行全盤掃描,這個過程是比較耗時的。

    清除階段清理的是沒有被引用的物件,存活的物件被保留。

    標記-清除動作不需要移動物件,且僅對不存活的物件進行清理,在空間中存活物件較多的時候,效率較高,但由於只是清除,沒有重新整理,因此會造成記憶體碎片。

    標記-壓縮:該演算法與標記-清除演算法類似,都是先對存活的物件進行標記,但是在清除後會把活的物件向左端空閒空間移動,然後再更新其引用物件的指標,如下圖所示

    由於進行了移動規整動作,該演算法避免了標記-清除的碎片問題,但由於需要進行移動,因此成本也增加了。(該演算法適用於舊生代)

    3),虛擬機器中GC的過程:

    1,在初始階段,新建立的物件被分配到Eden區,survivor的兩塊空間都為空。

    2,當Eden區滿了的時候,minor garbage 被觸發 。

    3,經過掃描與標記,存活的物件被複制到S0,不存活的物件被回收

    4,在下一次的Minor GC中,Eden區的情況和上面一致,沒有引用的物件被回收,存活的物件被複制到survivor區。然而在survivor區,S0的所有的資料都被複制到S1,需要注意的是,在上次minor GC過程中移動到S0中的兩個物件在複製到S1後其年齡要加1。此時Eden區S0區被清空,所有存活的資料都複製到了S1區,並且S1區存在著年齡不一樣的物件,過程如下圖所示:

    5,再下一次MinorGC則重複這個過程,這一次survivor的兩個區對換,存活的物件被複制到S0,存活的物件年齡加1,Eden區和另一個survivor區被清空。

    6,再經過幾次Minor GC之後,當存活物件的年齡達到一個閾值之後(可透過引數配置,預設是8),就會被從年輕代Promotion到老年代。

    7,隨著MinorGC一次又一次的進行,不斷會有新的物件被promote到老年代。

    8,上面基本上覆蓋了整個年輕代所有的回收過程。最終,MajorGC將會在老年代發生,老年代的空間將會被清除和壓縮。

    4),Minor GC,Major GC,Full GC觸發條件

    Minor GC:當年輕代中的Eden區滿時,觸發;

    Major GC:清理老年代,通常由Minor GC觸發;

    Full GC:

    (1)呼叫System.gc時,建議執行full GC,但是不一定執行;

    (2)老年代空間不足,

    (3)方法區空間不足,

    (4)透過Minor GC進入老年代的平均大小大於老年代的可用記憶體;

    (5)Minor GC觸發Full GC:新生代的eden區和suvivor(使用中)向survivor(暫未使用)複製物件的時候,大於survivor(暫未使用)的記憶體,隨即把物件轉存到老年代,但同樣大於老年代的可用永存

    5),JVM引數與調優:

    JVM引數:

    -Xmx:最大允許分配堆記憶體;

    -Xms:初始分配的堆記憶體; 通常與Xmx一樣,避免每次GC後重新分配記憶體

    CMSFullGCsBeforeCompaction=5:會每隔5次真正的full GC做一次壓縮

    -XX:CMSInitiatingOccupancyFraction=70 是指設定CMS在對記憶體佔用率達到70%的時候開始GC(因為CMS會有浮動垃圾,所以一般都較早啟動GC);

    -XX:+CMSParallelRemarkEnabled 減少第二次暫停的時間,開啟並行的remark;

    -XX:+DisableExplicitGC 禁止程式碼中顯式的呼叫GC,

    -XX:+DoEscapeAnalysis 開啟逃逸(例如被靜態變數引用等導致無法回收)分析

    XX:+UseCMSCompactAtFullCollection 開啟碎片合併

    XX:+UseConcMarkSweepG 使用CMS收集器

    -XX:+UseParNewGC 年輕代為多執行緒收集。

    還有更多的JAVA乾貨技術分享,敬請關注。。。

  • 中秋節和大豐收的關聯?
  • 一年級語文應該如何教?