1. 程式人生 > >Java:JVM垃圾回收機制

Java:JVM垃圾回收機制

JVM垃圾回收機制
提到Java垃圾回收機制就不得不提到一個方法: system.gc() 用於呼叫垃圾收集器,在呼叫時垃圾收集器將執行以回收未使用的記憶體空間,它將嘗試釋放被丟棄物件所佔用的空間。
作為程式設計師有必要了解gc方法,這也是在面試中經常會被問及的問題: 我們從三個方面來理解gc: 1.JVM如何確定哪些空間能被回收? 2.JVM會在什麼時候進行垃圾清除的動作? 3.JVM如何清除垃圾的?

1.JVM如何確定哪些空間能被回收 通過兩個演算法:
  • 引用計數演算法:
     簡單的來說就是判斷物件的引用數量。實現方式:給物件共新增一個引用計數器,每當有引用對他進行引用時,計數器的值就加
    1,當引用失效,也就是不在執行此物件是,他的計數器的值就減1,若某一個物件的計數器的值為0,那麼表示這個物件沒有人對他進行引用,也就是意味著是一個失效的垃圾物件,就會被gc進行回收。  但是這種簡單的演算法在當前的jvm中並沒有採用,原因是他並不能解決物件之間迴圈引用的問題。  假設有AB兩個物件之間互相引用,也就是說A物件中的一個屬性是BB中的一個屬性時A,這種情況下由於他們的相互引用,從而是垃圾回收機制無法識別。
  • 可達性分析演算法:
    因為引用計數法的缺點有引入了可達性分析演算法,通過判斷物件的引用鏈是否可達來決定物件是否可以被回收。可達性分析演算法是從離散數學中的圖論引入的,程式把所有的引用關係看作一張圖,通過一系列的名為
    GC Roots的物件作為起始點,從這些節點開始向下搜尋,搜尋所走過的路徑稱為引用鏈。當一個物件到 GC Roots 沒有任何引用鏈相連(就是從 GC Roots 到這個物件不可達)時,則證明此物件是不可用的。

2.JVM會在什麼時候進行垃圾清除的動作
  • 會在cpu空閒的時候自動進行回收
  • 在堆記憶體儲存滿了之後
  • 主動呼叫System.gc()後嘗試進行回收(不一定成功)

3.JVM如何清除垃圾的? 通過四個演算法:
  1. 標記-清除演算法:
標記 所有需要回收的物件,然後 清除 標記的物件
缺點:會產生 空間碎片 ,資源浪費
  1. 複製演算法
記憶體分為兩塊 ,當使用的一塊滿了就將 存活物件 複製到另一塊中,再將使用的那一塊清空 缺點:記憶體縮小約為原來的一半

  1. 標記-整理演算法
標記 所有需要回收的物件,然後 清除 標記的物件,再將剩下的 存活物件整理 ,避免了空間碎片的產生
  1. 分代收集演算法
分代收集演算法是比較智慧的垃圾回收演算法,也是現在JVM使用最多的演算法,他本身其實並不算是一種演算法,而是會在具體的場景上選擇上面三種方法來進行垃圾回收 “代”指的是 新生代、老年代、永久代 【新生代】 按8:1:1分為 eden、survivorl0、survivor1 三個區域 一般情況下所有新生成的物件都存放於新生代 在新生代中,每次垃圾收集時都發現有 大批物件死去 ,只有少量存活,那就選用複製演算法。只需要付出少量 存活物件 的複製成本就可以完成收集。 【老年代】 老年代中存放的一般都是生存週期比較長的物件 老年代中因為 物件存活率高 、沒有額外空間對他進行分配擔保,就必須用標記 - 清除或者標記 - 整理 【永久代】 主要用來存放靜態檔案 【注意】在jdk8的時候Java廢棄了永久代,同時提供了與永久代類似的叫做“元空間”的技術。元空間的本質和永久代類似。不過元空間與永久代之間最大的區別在於:元空間並不在虛擬機器中,而是使用本地記憶體。也就是不侷限於 jvm 可以使用系統的記憶體。理論上取決於 32 / 64 位系統可虛擬的記憶體大小。