JVM學習筆記——垃圾回收篇

JVM學習筆記——垃圾回收篇在本系列內容中我們會對JVM做一個系統的學習 , 本片將會介紹JVM的垃圾回收部分
我們會分為以下幾部分進行介紹:

  • 判斷垃圾回收對象
  • 垃圾回收算法
  • 分代垃圾回收
  • 垃圾回收器
  • 垃圾回收調優
判斷垃圾回收對象本小節將會介紹如何判斷垃圾回收對象
引用計數法首先我們先來介紹引用計數法的定義:
  • 我們為對象附上一個當前使用量
  • 當有線程使用時,我們將該值加一;當線程停止使用時,我們將該值減一
  • 當當前使用量大于零時,我們創建該對象;當當前使用量減少為零時,我們將該對象當作垃圾回收對象
但該方法存在一個致命問題:
  • 當兩個對象互相調用對方時,就會導致當前使用量一直不為空,占用內存
可達性分析算法同樣我們先來簡單介紹可達性分析算法:
  • 我們首先判定一些對象為Root對象
  • 我們根據這些對象來選擇判定其他對象是否為垃圾回收對象
  • 當該對象直接或間接被Root對象所引用時,我們不設置為垃圾回收對象;當沒有被Root對象連接時 , 設置為垃圾回收對象
然后我們來簡單介紹一下Root對象的分類(來自MAT工具統計):
  • System Class:直屬于Java包下的相關類,包括有Object,String,Stream,Buffer等
  • Native Stack:直屬于操作系統交互的類,包括有wait等
  • Busy Monitor:讀鎖機制相關的類,當前狀態下被鎖定的對象是無法當作垃圾回收對象的
  • Thread:互動線程,線程相關的類也無法當作垃圾回收對象
可達性分析算法就是目前Java虛擬機所使用的垃圾回收器判定方法
五種引用下面我們將會介紹JVM中常用的五種引用方法,他們分別對應著不同的回收對象判定情況:
JVM學習筆記——垃圾回收篇

文章插圖
我們下面來一一介紹
強引用上述圖片中的A1對象就是強引用示例
我們下面介紹強引用的概念:
  • 強引用就是由Root對象直接引用的對象
然后我們介紹強引用的回收概念:
  • 只有當所有強引用連接都消失時,該對象才會被列為垃圾回收對象
  • 例如上圖 , A1對象由B,C兩個對象所強引用連接,只有當兩個對象都取消引用后 , A1對象才會被列入回收對象
軟引用上述圖片中的A2對象就是軟引用示例
我們下面介紹軟引用的概念:
  • 軟引用不是由根Root直接引用,而是采用一個軟引用對象SoftReference連接
然后我們介紹軟引用的回收概念:
  • 當該對象沒有被強引用連接,被軟引用連接時有可能會被回收
  • 每次發生垃圾回收 , 如果垃圾回收后的內存夠用 , 則不進行軟引用對象的垃圾回收;若內存不足,則進行軟引用對象的垃圾回收
此外我們的軟引用對象也是會占用內存的,所以我們也需要采用其他方法將軟引用對象回收:
  • 我們通常將軟引用對象綁定一個引用隊列
  • 當該軟引用對象不再連接任何對象時,將其放入引用隊列 , 引用隊列會進行檢測,檢測到軟引用對象就會對其進行垃圾回收
我們首先給出軟引用對象的相關測試代碼:
package cn.itcast.jvm.t2;import java.io.IOException;import java.lang.ref.SoftReference;import java.util.ArrayList;import java.util.List;/** * 演示軟引用 * -Xmx20m -XX:+PrintGCDetails -verbose:gc */public class Demo2_3 {private static final int _4MB = 4 * 1024 * 1024;public static void main(String[] args) throws IOException {// 這部分是強引用對象,我們會發現所有內存都放在內部 , 導致內存不足List<byte[]> list = new ArrayList<>();for (int i = 0; i < 5; i++) {list.add(new byte[_4MB]);}System.in.read();// 調用下列方法(軟引用)soft();}// 軟引用public static void soft() {// 軟引用邏輯:list --> SoftReference --> byte[]// 創建軟引用List<SoftReference<byte[]>> list = new ArrayList<>();for (int i = 0; i < 5; i++) {// 首先new一個SoftReference并賦值SoftReference<byte[]> ref = new SoftReference<>(new byte[_4MB]);System.out.println(ref.get());// 將SoftReference加入listlist.add(ref);System.out.println(list.size());}System.out.println("循環結束:" + list.size());for (SoftReference<byte[]> ref : list) {System.out.println(ref.get());}}}/*調試過程:如果我們采用強引用方法,正常情況下會在第五次循環時報錯但是如果我們采用軟引用,我們會在第五次循環時發生gc清理,這時我們前四次的添加(list的前四位)就會被軟引用清除所以我們在最后循環結束后查看數組會發現:nullnullnullnull[B@330bedb4*/

推薦閱讀