《Java核心技術面試精講》27講學習總結

e1122334455發表於2021-01-03

第27講心得

該講介紹了Java 常見的垃圾收集器。                                                                                                                                                                  

  1. 於物件例項收集,主要是兩種基本演算法,引用計數和可達性分析。引用計數演算法,顧名思義,就是為物件新增一個引用計數,用於記錄物件被引用的情況,如果計數為 0,即表示物件可回收。這是很多語言的資源回收選擇,例如因人工智慧而更加火熱的 Python,它更是同時支援引用計數和垃圾收集機制。具體哪種最優是要看場景的,業界有大規模實踐中僅保留引用計數機制,以提高吞吐量的嘗試。Java 並沒有選擇引用計數,是因為其存在一個基本的難題,也就是很難處理迴圈引用關係。另外就是 Java 選擇的可達性分析,Java 的各種引用關係,在某種程度上,將可達性問題還進一步複雜化,具體請參考專欄第 4 講,這種型別的垃圾收集通常叫作追蹤性垃圾收集(Tracing Garbage Collection)。其原理簡單來說,就是將物件及其引用關係看作一個圖,選定活動的物件作為 GC Roots,然後跟蹤引用鏈條,如果一個物件和 GC Roots 之間不可達,也就是不存在引用鏈條,那麼即可認為是可回收物件。JVM 會把虛擬機器棧和本地方法棧中正在引用的物件、靜態屬性引用的物件和常量,作為 GC Roots。
  2. 常見的垃圾收集演算法主要分為三類:複製(Copying)演算法,我前面講到的新生代 GC,基本都是基於複製演算法,過程就如專欄上一講所介紹的,將活著的物件複製到 to 區域,拷貝過程中將物件順序放置,就可以避免記憶體碎片化。這麼做的代價是,既然要進行復制,既要提前預留記憶體空間,有一定的浪費;另外,對於 G1 這種分拆成為大量 region 的 GC,複製而不是移動,意味著 GC 需要維護 region 之間物件引用關係,這個開銷也不小,不管是記憶體佔用或者時間開銷。標記 - 清除(Mark-Sweep)演算法,首先進行標記工作,標識出所有要回收的物件,然後進行清除。這麼做除了標記、清除過程效率有限,另外就是不可避免的出現碎片化問題,這就導致其不適合特別大的堆;否則,一旦出現 Full GC,暫停時間可能根本無法接受。標記 - 整理(Mark-Compact),類似於標記 - 清除,但為避免記憶體碎片化,它會在清理過程中將物件移動,以確保移動後的物件佔用連續的記憶體空間。

相關文章