JVM必備基礎知識(三)-- GC垃圾回收機制

本章內容是對《深刻理解Java虛擬機:JVM高級特性和最佳實踐》的理解和歸納。java

前言

前文中咱們講過了類加載器和雙親委派,那麼接下來介紹的就是GC垃圾回收機制。git

Java內存模型

在此以前咱們須要知道GC回收機制回收的是什麼?他們的存儲形式是什麼樣的?等等一系列問題。因此引入了內存模型的概念。 github

Java內存模型

5大區域各自的做用:算法

  1. 程序計數器:指示當前線程所執行的字節碼執行到了第幾行。
  2. 虛擬機棧:爲執行的方法建立棧幀,保存了局部變量表、操做站、動態連接、方法出口等信息,主要用來執行Java方法。
  3. 本地方法棧:運行方法與虛擬機棧類似,主要用來執行native方法。
  4. 堆區:用於存儲對象的實例。
  5. 方法區:存儲已經被虛擬機加載的類信息(即加載類時須要加載的信息,包括版本、field、方法、接口等信息)、final常量、靜態變量、編譯器即時編譯的代碼等。

Object做爲全部類的父類以他建立一個對象,將涉及哪些區域的變更呢?緩存

Object obj = new Object();
複製代碼

①、Object obj表示一個本地引用,存儲在虛擬機棧的本地變量表中,表示一個reference類型數據; ②、new Object()做爲實例對象數據存儲在堆中,另外還記錄了Object類的類型信息(接口、方法、field、對象類型等)的地址,這些地址所執行的數據存儲在方法區中;框架

GC回收機制

既然要垃圾回收,那到底要回收的是哪些東西呢? 上文中Object類的舉例,已經有必定的苗頭了。 在方法區中的數據,是從一開始就要求被加入的,那麼回收掉他們不免會出現各類問題。而像Object這樣的類,只在一段時間內須要被使用,也就不免會成爲多出來的碎片,也就成了典型的「佔着茅坑不拉屎」的了。 因此,顯而易見,咱們要回收的就是這麼一類垃圾數據了,而GC回收器回收的也就是這種new出來之後沒用了的數據了。工具

堆區的細節劃分

  • 新生代:Eden 、From Space、To Space 剛建立的對象通常都被放入Eden中,Eden滿了之後,就會進行一次GC操做,刪去消亡的,把活躍的放到From中。(To Space和From Space是一個輪換的,空的那份數據就是下一輪Eden滿時要存放數據的From Space,另一個就成了To Spcae)To Space滿了的時候就會將對象轉移到老年代。
  • 老年代 通過了屢次回收,但仍是堅強存活下來的對象們所在的內存空間。

對象存活判斷

引用計數

一個對象被引用時加一,被去除引用時減一。那麼當數值爲0時,這個引用就成爲了一個垃圾。 問題,若是存在循環引用時,就不會結束引用。post

// A類持有B的引用
public class A {
    B b;
}
// B類一樣持有A的引用
public class B {
    A a;
}
// 具體使用
public class Main {
    public static void main(String[] args) {
        A a = new A();
        B b = new B();
        a.b = b;
        b.a = a;
    }
}
複製代碼

像上述的代碼中,引用計數就徹底沒法進行斷定。性能

可達性分析

經過對一類的GC Roots鏈表遍歷,經過可達性來斷定是否爲垃圾。 GC Roots通常包括以下:學習

  • 虛擬機棧中引用的對象
  • 方法區靜態屬性引用的對象
  • 方法區常量引用的對象
  • JNI引用的對象(Native方法)

回收算法

複製收集

這是一個應用於新生代內存整理的方法。 由於新生代的Eden區是一個連續的內存空間,經過遍歷,把這個內存空間的消亡的對象刪去,活躍的對象們從新放入一個新的空白內存空間中。 也就是To Space和From Space的相互交換。 存在問題:內存摺半。

標記清理

這是一個應用於老年代內存整理的方法。

如圖所示,搜索出活躍的對象,清除消亡對象。 存在問題:會產生空間碎片。

標記整理

這是一個應用於老年代內存整理的方法。

比標記清理算法多一點,他須要排序。 存在問題:用性能換取空間碎片的整理。

Java引用

Java引用的分類主要也是響應了回收器的存在,通常分爲如下四類:

  • 強飲用:通常爲使用關鍵詞new實例化的對象,這類引用GC回收器寧肯溢出,也不會回收。
  • 軟引用:有用可是沒必要要的對象們,只有在內存不足時,纔會被GC回收器回收。通常使用於緩存各類資源。
public class Main {
    public static void main(String[] args) {
        SoftReference<String> sr = new SoftReference<String>(new String("SoftReference"));
        System.out.println(sr.get());
    }
}
複製代碼
  • 弱引用:GC發生時就會被回收的對象們,是一種防治oom的方法。弱引用的應用場景在個人Android工具包MVP框架中使用到。
public class Main {
    public static void main(String[] args) {
        WeakReference<String> sr = new WeakReference<String>(new String("WeakReference"));
        System.out.println(sr.get());
        // gc回收後再次查看效果
        System.gc();                
        System.out.println(sr.get());
    }
}
複製代碼
  • 虛引用:形同虛設的引用。

上面三種講的很清楚了,可是這個虛引用到底有什麼用呢? 它的做用在於跟蹤垃圾回收過程,在對象被收集器回收時收到一個系統通知。 當垃圾回收器準備回收一個對象時,若是發現它還有虛引用,就會在垃圾回收後,將這個虛引用加入引用隊列,在其關聯的虛引用出隊前,不會完全銷燬該對象。 因此能夠經過檢查引用隊列中是否有相應的虛引用來判斷對象是否已經被回收了。

以上就是個人學習成果,若是有什麼我沒有思考到的地方或是文章內存在錯誤,歡迎與我分享。


相關文章推薦:

JVM必備基礎知識(一)-- 類的加載機制

JVM必備基礎知識(二)-- 類加載器和雙親委派模型

相關文章
相關標籤/搜索