JVM系列擴展:常見垃圾回收算法

對象存活算法

在回收垃圾對象以前,垃圾收集器須要確認哪些對象「存活」和那些對象應該被回收算法

引用計數(Reference Counting)

引用計數是最古老的一種算法,在微軟的COM組件技術,Adobe的ActionScript3中都有使用。實現就是:對於一個對象A,只要任何一個對象引用了A,則A的引用計數器就加1;當引用失效時,引用計數器就減1;當一個對象的計數器值爲0時,則對象A則不可能再被使用。性能

引用計數的缺點在於:優化

  • 沒法處理循環引用的狀況,例如A引用了B,B引用了A,可是系統中不存在任何第3個對象引用了A,B(此時A,B應該是要被回收的),可是A,B的計數器都爲1,沒法被回收。
  • 引用計數器要求每次引用產生或者消除時,都須要作相應的加減運算,會對系統性能產生影響。

可達性分析算法 (Reachability Analysis)

在主流的商用程序語言的主流實現中,都是經過可達性分析來判斷一個對象是否應該存活的。其基本思想就是經過一系列的稱爲「GC Roots」的對象做爲根節點,從這些節點開始向下搜索,搜索所走過的路徑稱爲「引用鏈」。當一個對象到「GC Roots」沒有任何的引用鏈相連時,則證實此對象能夠被回收。code

在Java虛擬機中,可做爲GC Roots的對象包括如下幾種:對象

  • 虛擬機棧(棧幀中局部變量表)中引用的對象
  • 方法區中類靜態屬性引用的對象
  • 方法區中常量引用的對象
  • 本地方法棧中JNI(即通常說的native方法)引用的對象

擴展:Java語言的四種引用類型:強引用,軟引用,弱引用,虛引用ip

垃圾回收算法

標記清除算法(Mark-Sweep)

標記清除算法將垃圾回收分爲標記清除兩個階段。在標記階段,標記全部從根節點開始的可達對象,此時未標記的對象即爲垃圾對象,等待回收。在清除階段,清除全部的未標記對象。內存

標記清除的缺點在於:虛擬機

  • 回收後的空間容易產生空間碎片

複製算法(Copying)

複製算法的核心思想是將原有的內存空間分爲兩塊,每次只使用其中的一塊,在垃圾回收時,將存活的對象複製到另外一塊未被使用的空間,以後清除原來使用的空間中的全部對象。it

複製算法的優勢:io

  • 若是系統的垃圾對象多,複製算法要複製的存貨對象就少,所以效率會高
  • 不會產生空間碎片

缺點:

  • 可用內存摺半,老是存在一塊內存不被使用

在Java虛擬機新生代串行垃圾回收器中,使用了複製算法的思想。新生代被分爲eden,from,to三個內存空間。其中fromto是兩塊大小至關,地位相同且可進行角色互換的空間,也統稱爲survivor空間。

標記壓縮算法 (Mark-Compact)

相比於複製算法存活對象少,垃圾對象多的狀況,標記壓縮算法一般用於大部分對象都是存活對象的狀況(老年代的回收算法)。它在標記清除算法的基礎上作了一些優化,在標記存活對象後,將全部的對象壓縮到內存的一端,而後再清除邊界外的全部空間。

優勢:

  • 避免產生碎片
  • 內存使用率高,不存在內存摺半的現象

由於只是比標記清除多了一個壓縮的步驟,因此也被稱爲標記清除壓縮算法(MarkSweepCompact)

分代算法 (Generational Collecting)

在上面的一系列算法中,並無哪一種算法能夠徹底的替代其餘的算法。它們各自具有本身獨特的優點和特色。所以,將內存區間根據對象的特色分紅幾塊,每塊使用不一樣的回收算法,以提升垃圾回收效率,這就是分代算法。

在Java虛擬機中,全部的新建對象都會優先存放在新生代內存空間中,對於新生代內存空間中的對象,很容易就被回收,所以新生代適合複製算法。當一個對象通過幾回回收後仍然存活,該對象就會被放入老年代內存空間,在老年代內存空間的對象,通過幾回垃圾回收後仍然存活的機率一般很大,根據分代的思想,老年代適合標記壓縮或標記清除算法

相關文章
相關標籤/搜索