【年終總結】11組關係帶你看清JVM全貌

關注「Java後端技術全棧」java

回覆「面試」獲取全套面試資料面試

廢話少說,直接開整:算法

第1組:JDKJREJVM的關係

JDK中包含JRE,也包括JDK,而JRE也包括JDK後端

範圍關係:JDK>JRE>JVM緩存

具體見下圖:數據結構

圖片

第2組:.java文件與.class文件的關係

這二者的關係須要兩張圖才能說明白:jvm

圖片

第3組:class文件與JVM的關係

JVM經過類加載機制,把class文件裝載進JVM中,而後JVM解析class文件的內容,因而就有了類加載過中的連接、初始化等。源碼分析

第4組:類加載器關係

一張圖來講明:編碼

第5組:方法區、堆、棧之間到底有什麼關係

直接上圖:spa

圖片

棧指向堆

若是在棧幀中有一個變量,類型爲引用類型,好比:

package com.tian.my_code.test;
public class JvmCodeDemo {
    public  Object testGC(){
        int op1 = 10;
        int op2 = 3;
        Object obj = new Object();
        Object result=obj;
        return result;
    }
}

這時候就是典型的棧中元素obj指向堆中的Object對象,result的指向和obj的指向爲同一個對象。

圖片

使用命令

javac -g:vars JvmCodeDemo.java

進行編譯,而後再使用

javap -v JvmCodeDemo.class >log.txt

而後打開log.txt文件

方法區指向堆

方法區中會存放靜態變量,常量等數據。

若是是下面這種狀況,就是典型的方法區中元素指向堆中的對象。

圖片

堆指向方法區

方法區中會包含類的信息,對象保存再堆中,建立一個對象的前提是有對應的類信息,這個類信息就在方法區中。

圖片

第6組:Minor、Major、Full GC的關係

Minor GC:發生在年輕代的 GC。

  • Minor GC是指從年輕代空間(包括 Eden 和 Survivor 區域)回收內存。當 JVM 沒法爲一個新的對象分配空間時會觸發Minor GC,好比當 Eden 區滿了。
  • Eden區滿了觸發MinorGC,這時會把Eden區存活的對象複製到Survivor區,當對象在Survivor區熬過必定次數的MinorGC以後,就會晉升到老年代(固然並非全部的對象都是這樣晉升的到老年代的),當老年代滿了,就會報OutofMemory異常。
  • 全部的MinorGC都會觸發全世界的暫停(stop-the-world),中止應用程序的線程,不過這個過程很是短暫。

Major GC:發生在老年代的 GC。

  • Major GC清理Tenured區(老年代)。

Full GC:新生代+老年代,好比 方法區引發年輕代和老年代的回收。

第7組:Survivor與Eden的關係

對於這二者,最重要的是要明白爲何須要Survivor區?只有Eden不行嗎?

若是沒有Survivor,Eden區每進行一次Minor GC ,而且沒有年齡限制的話, 存活的對象就會被送到老年代。這樣一來,老年代很快被填滿,觸發Major GC(由於Major GC通常伴隨着Minor GC,也能夠看作觸發了Full GC)。老年代的內存空間遠大於新生代,進行一次Full GC消耗的時間比Minor GC長得多。

執行時間長有什麼壞處?

頻發的Full GC消耗的時間很長,會影響大型程序的執行和響應速度。

可能你會說,那就對老年代的空間進行增長或者較少咯。

假如增長老年代空間,更多存活對象才能填滿老年代。雖然下降Full GC頻率,可是隨着老年代空間加大,一旦發生Full GC,執行所須要的時間更長。

假如減小老年代空間,雖然Full GC所需時間減小,可是老年代很快被存活對象填滿,Full GC頻率增長。

因此Survivor的存在乎義,就是減小被送到老年代的對象,進而減小Full GC的發生,Survivor的預篩選保證,只有經歷16 次Minor GC還能在新生代中存活的對象,纔會被送到老年代。

第8組:引用計數法和可達性分享算法的關係

引用計數法

給對象添加一個引用計數器,每當一個地方引用它object時技術加1,引用失去之後就減1,計數爲0說明再也不引用

  • 優勢:實現簡單,斷定效率高
  • 缺點:沒法解決對象相互循環引用的問題,對象A中引用了對象B,對象B中引用對象A。

public class A {
    public B b; 
}
public class B {
    public C c; 
}
public class C {
    public A a; 
}
public class Test{
    
    private void test(){
        A a = new A();
        B b = new B();
        C c = new C();
        
        a.b=b;
        b.c=c;
        c.a=a;
    }
}

可達性分析算法

當一個對象到GC Roots沒有引用鏈相連,即就是GC Roots到這個對象不可達時,證實對象不可用。

圖片

GC Roots種類:

Java 線程中,當前全部正在被調用的方法的引用類型參數、局部變量、臨時值等。也就是與咱們棧幀相關的各類引用。全部當前被加載的 Java 類。Java 類的引用類型靜態變量。運行時常量池裏的引用類型常量(String 或 Class 類型)。JVM 內部數據結構的一些引用,好比 sun.jvm.hotspot.memory.Universe 類。用於同步的監控對象,好比調用了對象的 wait() 方法。

第9組:對象的引用類型的關係

  • 強引用:User user=new User();咱們開發中使用最多的對象引用方式。

    特色:咱們日常典型編碼Object obj = new Object()中的obj就是強引用。

    經過關鍵字new建立的對象所關聯的引用就是強引用。

    JVM內存空間不足,JVM寧願拋出OutOfMemoryError運行時錯誤(OOM),使程序異常終止,也不會靠隨意回收具備強引用的「存活」對象來解決內存不足的問題。

    對於一個普通的對象,若是沒有其餘的引用關係,只要超過了引用的做用域或者顯式地將相應(強)引用賦值爲 null,就是能夠被垃圾收集的了,具體回收時機仍是要看垃圾收集策略。

  • 軟引用:SoftReference<Object> object=new SoftReference<Object>(new Object());

    特色:軟引用經過SoftReference類實現。軟引用的生命週期比強引用短一些。只有當 JVM 認爲內存不足時,纔會去試圖回收軟引用指向的對象:即JVM 會確保在拋出 OutOfMemoryError 以前,清理軟引用指向的對象。軟引用能夠和一個引用隊列(ReferenceQueue)聯合使用,若是軟引用所引用的對象被垃圾回收器回收,Java虛擬機就會把這個軟引用加入到與之關聯的引用隊列中。後續,咱們能夠調用ReferenceQueue的poll()方法來檢查是否有它所關心的對象被回收。若是隊列爲空,將返回一個null,不然該方法返回隊列中前面的一個Reference對象。

    應用場景:軟引用一般用來實現內存敏感的緩存。若是還有空閒內存,就能夠暫時保留緩存,當內存不足時清理掉,這樣就保證了使用緩存的同時,不會耗盡內存

  • 弱引用:WeakReference<Object> object=new WeakReference<Object> (new Object();ThreadLocal中有使用.

    弱引用經過WeakReference類實現。弱引用的生命週期比軟引用短。在垃圾回收器線程掃描它所管轄的內存區域的過程當中,一旦發現了具備弱引用的對象,無論當前內存空間足夠與否,都會回收它的內存。因爲垃圾回收器是一個優先級很低的線程,所以不必定會很快回收弱引用的對象。

    弱引用能夠和一個引用隊列(ReferenceQueue)聯合使用,若是弱引用所引用的對象被垃圾回收,Java虛擬機就會把這個弱引用加入到與之關聯的引用隊列中。應用場景:弱應用一樣可用於內存敏感的緩存。

  • 虛引用:幾乎沒見過使用, ReferenceQueue 、PhantomReference

第10組:垃圾回收算法的關係

標記-清除算法

第一步:就是找出活躍的對象。咱們反覆強調 GC 過程是逆向的, 根據 GC Roots 遍歷全部的可達對象,這個過程,就叫做標記。

第二部:除了上面標記出來的對象之外,其他的都清楚掉。

  • 缺點:標記和清除效率不高,標記和清除以後會產生大量不連續的內存碎片

圖片

複製算法

新生代使用,新生代分中Eden:S0:S1= 8:1:1,其中後面的1:1就是用來複制的。

當其中一塊內存使用完了,就將還存活的對象複製到另一塊上面,而後把已經使用過的內存空間一次 清除掉。

圖片

通常對象分配都是進入新生代的eden區,若是Minor GC還存活則進入S0區,S0S1不斷對象進行復制。對象存活年齡最大默認是15,大對象進來可能由於新生代不存在連續空間,因此會直接接入老年代。任何使用都有新生代的10%是空着的。

  • 缺點:對象存活率高時,複製效率會較低,浪費內存。

標記整理算法

它的主要思路,就是移動全部存活的對象,且按照內存地址順序依次排列,而後將末端內存地址之後的內存所有回收。 可是須要注意,這只是一個理想狀態。對象的引用關係通常都是很是複雜的,咱們這裏不對具體的算法進行描述。咱們只須要了解,從效率上來講,通常整理算法是要低於複製算法的。這個算法是規避了內存碎片和內存浪費。

讓全部存活的對象都向一端移動,而後直接清理掉端邊界之外的內存。

從上面的三個算法來看,其實沒有絕對最好的回收算法,只有最適合的算法。

第11組:垃圾收集器之間有什麼關係

「新生代收集器」:Serial、ParNewParallel Scavenge

「老年代收集器」CMS、Serial Old、Parallel Old

「整堆收集器」G1ZGC(由於不涉年代不在圖中)

圖片

推薦閱讀

《算法圖解》.pdf

田哥:面試被問== 與equals 的區別,該怎麼回答?

《一本小小的MyBatis源碼分析書》.pdf

相關文章
相關標籤/搜索