Java虛擬機垃圾回收與算法

1、如何確定垃圾

  • 引用計數法:在 Java 中,引用和對象是有關聯的。如果要操作對象則必須用引用進行。因此,一個簡單的辦法是通過引用計數來判斷一個對象是否可以回收。簡單說,即一個對象如果沒有任何與之關聯的引用,即他們的引用計數都不爲 0,則說明對象不太可能再被用到,那麼這個對象就是可回收對象。
  • 可達性分析:爲了解決引用計數法的循環引用問題,Java 使用了可達性分析的方法。通過一系列的“GC roots” 對象作爲起點搜索。如果在“GC roots”和一個對象之間沒有可達路徑,則稱該對象是不可達的。要注意的是,不可達對象不等價於可回收對象,不可達對象變爲可回收對象至少要經過兩次標記過程。兩次標記後仍然是可回收對象,則將面臨回收。

2、標記清除算法(Mark-Sweep)

majorGC中使用該算法

  • 最基礎的垃圾回收算法,分爲兩個階段,標記和清除。標記階段標記出所有需要回收的對象,清除階段回收被標記的對象所佔用的空間。從圖中我們就可以發現,該算法最大的問題是內存碎片化嚴重,後續可能發生大對象不能找到可利用空間的問題。
  • image.pngimage.png

3、複製算法(copying)

MinorGC中使用該算法

  • 爲了解決 Mark-Sweep 算法內存碎片化的缺陷而被提出的算法。按內存容量將內存劃分爲等大小的兩塊。每次只使用其中一塊,當這一塊內存滿後將尚存活的對象複製到另一塊上去,把已使用的內存清掉,這種算法雖然實現簡單,內存效率高,不易產生碎片,但是最大的問題是可用內存被壓縮到了原本的一半。且存活對象增多的話,Copying 算法的效率會大大降低。

4、標記整理算法(Mark-Compact)

  • 結合了以上兩個算法,爲了避免缺陷而提出。標記階段和 Mark-Sweep 算法相同,標記後不是清理對象,而是將存活對象移向內存的一端。然後清除端邊界外的對象。
  • image.png

5、分代收集算法

  • 分代收集法是目前大部分 JVM 所採用的方法,其核心思想是根據對象存活的不同生命週期將內存 劃分爲不同的域,一般情況下將 GC 堆劃分爲老生代(Tenured/Old Generation)和新生代(Young Generation)。老生代的特點是每次垃圾回收時只有少量對象需要被回收,新生代的特點是每次垃 圾回收時都有大量垃圾需要被回收,因此可以根據不同區域選擇不同的算法。
  • 新生代與複製算法:
  • 目前大部分 JVM 的 GC 對於新生代都採取 Copying 算法,因爲新生代中每次垃圾回收都要回收大部分對象,即要複製的操作比較少,但通常並不是按照 1:1 來劃分新生代。一般將新生代 劃分爲一塊較大的 Eden 空間和兩個較小的 Survivor 空間(From Space, To Space),每次使用 Eden 空間和其中的一塊 Survivor 空間,當進行回收時,將該兩塊空間中還存活的對象複製到另 一塊 Survivor 空間中。
  • 老年代與標記整理算法:老年代因爲每次只回收少量對象,因而採用 Mark-Compact 算法
  1. JAVA 虛擬機提到過的處於方法區的永生代(Permanet Generation),它用來存儲 class 類, 常量,方法描述等。對永生代的回收主要包括廢棄常量和無用的類。
  2. 對象的內存分配主要在新生代的 Eden Space 和 Survivor Space 的 From Space(Survivor 目 前存放對象的那一塊),少數情況會直接分配到老生代。
  3. 當新生代的 Eden Space 和 From Space 空間不足時就會發生一次 GC,進行 GC 後,Eden Space 和 From Space 區的存活對象會被挪到 To Space,然後將 Eden Space 和 From Space 進行清理。
  4. 如果 To Space 無法足夠存儲某個對象,則將這個對象存儲到老生代。
  5. 在進行 GC 後,使用的便是 Eden Space 和 To Space 了,如此反覆循環。
  6. 當對象在 Survivor 區躲過一次 GC 後,其年齡就會+1。默認情況下年齡到達 15 的對象會被移到老生代中

6、GC 分代收集算法 VS 分區收集算法

1、分代收集算法

  1. 當前主流 JVM 垃圾收集都採用”分代收集”(Generational Collection)算法, 這種算法會根據對象存活週期的不同將內存劃分爲幾塊, 如 JVM 中的新生代、老年代、永久代,這樣就可以根據各年代特點分別採用最適當的 GC 算法。

2、分區收集算法

  1. 分區算法則將整個堆空間劃分爲連續的不同小區間, 每個小區間獨立使用, 獨立回收。這樣做的好處是可以控制一次回收多少個小區間,根據目標停頓時間, 每次合理地回收若干個小區間(而不是 整個堆), 從而減少一次 GC 所產生的停頓。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章