JVM垃圾收集算法

JVM垃圾收集算法

1 對象是否是垃圾

判難斷對象是夠是垃圾一般有兩種算法:引用計數算法和可達性分析算法,JVM使用的可達性分析算法

1.1 引用計數算法

引用計數算法:給對象添加一個引用計數器,每當有一個地方引用它時,計數器值就加1;當引用失效時,計數器就減一;任何時刻計數器爲0的對象就是不可能再被使用的對象。
JVM沒有使用引用計數算法的主要原因是它很難解決對象之間相互循環引用的問題

1.2 可達性分析算法

可達性分析算法的思路:通過一系列稱爲“GC Roots”的對象作爲起點,從這些節點開始向下搜索,搜索所走過的路徑稱爲引用鏈,當一個對象到GC roots沒有任何引用鏈相連時,則證明對象是不可用的。
在Java語言中,作爲GC Roots的對象包括以下幾種:

  1. 虛擬機棧中引用的對象
  2. 方法區中類靜態屬性引用的對象
  3. 方法區中常量引用的對象
  4. 本地方法棧中JNI引用的對象

1.3 再談引用

在JDK1.2版本以後,Java對引用的概念進行了擴充,將引用分爲強引用,軟引用,弱引用,虛引用4種,這4種引用強度依次逐漸減弱

  • 強引用就是指在程序代碼中普遍存在的。類似Object obj= new Object();這類的引用,只要強引用存在,垃圾收集器永遠不會回收掉被引用的對象
  • 軟引用就是用來描述一些還有用但並非必需的對象。對於軟引用關聯的對象,在系統將要發生內存溢出異常之前,將會把這些對象列進可回收返回之中進行第二次回收。在JDK1.2以後,提供了SoftReference類來實現軟引用
  • 弱引用也是用來描述非必需對象的,但是強度比軟引用更弱一些,被弱引用關聯的對象只能生存到下一次垃圾收集發生之前。也即當垃圾收集器開始時,無論當前內存是否夠用,都會的回收掉只被弱引用關聯的對象。在JDK1.2版本以後,提供了WeakReference類來實現弱引用
  • 虛引用也就是幽靈引用或者幻影引用,它是最弱的一種引用關係。一個對象是否有虛引用的存在,完全不會對其生存時間構成影響,也無法通過虛引用來取得一個對象實例。爲一個對象設置虛引用關聯的唯一目的是能夠在這個對象被垃圾收集器回收時收到一個系統通知。在JDK1.2版本以後,提供了PhantomReference來實現虛引用。

1.4 finalize方法

即使可達性分析算法中不可達的對象,也不是非死不可,還可以有重生的機會。要宣佈一個對象死亡,必須經過兩個標記過程:
1.如果對象在進行可達性分析後發現沒有與GC Roots相連接的引用鏈,那它將會被第一次標記並且進行一次篩選,篩選條件是此對象是否有必要執行finalize方法。
2.當對象沒有覆蓋finalize方法,或者finalize方法已經被虛擬機調用過,虛擬機將這兩種都視爲“沒有必要執行”(任何一個對象的finalize方法只能被系統自動調用一次)。

如果這個對象被判斷爲有必要執行finalize方法,那麼這個對象將會放置在一個叫做F-Queue的隊列中,並稍後由一個虛擬機自動創建的低優先級的Finalizer線程去執行它。這裏的執行是指虛擬機會觸發這個方法,但並不承諾會等待它運行的結果,原因是如果finalize方法中執行緩慢或者死循環,將可能導致F-Queue隊列中其他對象永久處於等待。
finalize方法時對象逃脫死亡最後一次機會,稍後F-Queue中的對象進行第二次小規模的標記,如果對象在finalize中成功拯救了自己,那麼第二次標記時將會被移除即將回收的集合。

1.5 回收方法區

方法區的回收主要兩部分內容:廢棄常量和無用的類
廢棄常量
這個和Java堆中的對象相似,就是沒有任何String對象引用常量池中的常量字符串,常量池中其他類,方法,字段的符號引用也與之類似
無用的類
類需要同時滿足以下三個條件才能算是無用的類
(1)該類所有的實例都已經被回收,也就是Java堆中不存在該類的任何實例
(2)加載該類的ClassLoader已經被回收
(3)該類對應的Class對象沒有在任何地方被引用,無法在任何地方通過反射訪問該類的方法

2. 垃圾收集算法

2.1 標記-清除算法

算法分爲兩個階段:標記和清除。首先標記處所有需要回收的對象,在標記完成後統一回收所有被標記的對象。
標記算法存在兩個不足:(1)效率問題,標記和清除兩個過程的效率都不高(2)空間問題,標記清除之後會產生大量的不連續的內存碎片,空間碎片太多可能會導致以後在程序運行過程中需要分配較大對象時,無法分配到足夠的連續內存而不得不提前觸發另外一次垃圾回收的動作

2.2 複製算法

複製算法是把可用內存按容量劃分爲大小相等的兩塊,每次只使用其中的一塊。當這一塊內存用完了,就將還存活着的對象複製到另外一個上面。然後在把已使用過的內存空間一次性的清理掉。
算法缺點是內存使用大小縮短爲原來的一半。
現代的虛擬機都是採用這種複製算法來回收新生代,同時使用老年代進行分配擔保。

2.3 標記-整理算法

標記整理算法過程依然與標記清楚算法一樣,但是後續步驟不是直接對可回收的對象進行清理,而是讓所有存活的對象都向一段移動,然後在直接清理掉端邊界以外的內存。

2.4 分代收集算法

當前現在虛擬機的垃圾收集器都是採用的分代收集算法。一般把Java堆分爲新生代和老年代,這樣可以根據各個年代的特點採用最合適的收集算法。新生代的對象朝生夕死採用複製算法,老年代對象存活率高,就必須採用標記-整理或標記-清除算法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章