天天看點

JVM進階之GC(二)對象存活判斷算法

上一篇簡單的說明了對象在JVM中的記憶體分代政策,此文繼續來為GC打基礎,說說什麼樣的對象需要被GC,即對象是否存活判定算法。

判定對象存活算法

如何判斷對象淪為了垃圾也是門技術。

引用計數法

引用計數法就是給對象加個引用計數器,每有一個地方引用到它時,這個引用計數器就加1。當引用失效的時候,計數器的值就減1,也就是說根據引用計數器的值來判斷對象是否存活,若值是0,那麼該對象就不再被使用了。

真是如此嗎?答案是否定的。試想一下如下圖的場景:

JVM進階之GC(二)對象存活判斷算法

AB對象互相引用,那麼AB對象的引用計數器的值永遠都不會為0,AB就永遠都不會被回收,直接造成記憶體洩漏問題。是以該算法最大的缺點是

很難解決對象之間互相引用的問題

。但事實上,如上圖情況的互相引用對象會被回收,說明實際不是用引用計數法判定對象存活與否。

可達性分析法

可達性分析法的基本思路是通過一系列的GC Roots對象作為起始點,從這些點向下搜尋它們引用的對象,這樣可以生成一顆引用樹,樹的節點就是可達的對象。反之,不在樹上的對象即可判定對象已死。來看如下圖:

JVM進階之GC(二)對象存活判斷算法

D和E對象互相引用,但是它們沒有RC Roots根節點的引用指向,是以D和E在下次垃圾回收時會被處死,而ABC對象在GC Roots的引用樹上,會視為存活對象。

那麼哪些對象可以作為引用樹的根節點呢?

可作為GC Roots的對象

不難想象,作為GC Roots的對象必須是極難被回收的對象,包括了如下幾種對象:

  • 虛拟機棧(

    棧幀中的本地變量表

    )中引用的對象,如在方法中定義和使用的變量
  • 方法區中的

    類靜态屬性引用的對象

    ,如static修飾的成員變量
  • 方法區中

    常量引用的對象

    ,如static和final共同修飾的常量
  • 本地方法棧中

    JNI引用的對象

    ,JNI也就是調的native方法

引用類型與垃圾回收時機

不論是通過以上哪種方式判斷對象是否存活,都與

引用

相關。java自1.2之後,對引用劃分了4種,如下:

  • 強引用

    :隻要某個對象有強引用與之關聯,JVM必定不會回收這個對象,即使在記憶體不足的情況下,

    JVM甯願抛出OutOfMemory錯誤也不會回收

    這種對象。
  • 軟引用

    :軟引用是用來描述一些有用但并不是必需的對象,比如引用圖檔位址等,在Java中用java.lang.ref.SoftReference類來表示。對于軟引用關聯着的對象,

    隻有在記憶體不足的時候JVM才會回收

    該對象。
  • 弱引用

    :弱引用也是用來描述非必需對象的,當JVM進行垃圾回收時,無論記憶體是否充足,都會回收被弱引用關聯的對象。也就是說被弱引用關聯的對象,

    隻能生存到下一次垃圾收集發生之前

  • 虛引用(幽靈引用或幻影引用)

    :虛引用和前面的軟引用、弱引用不同,它并不影響對象的生命周期。在java中用java.lang.ref.PhantomReference類表示。如果一個對象與虛引用關聯,則跟沒有引用與之關聯一樣,在任何時候都可能被垃圾回收器回收。為一個對象設定虛引用關聯的

    唯一目的就是能在這個對象被收集器回收時收到一個系統通知

    。與弱引用差別:在GC時會被通知。

好了,今天點到為止,下篇談談垃圾回收算法和垃圾回收器。