上一篇簡單的說明了對象在JVM中的記憶體分代政策,此文繼續來為GC打基礎,說說什麼樣的對象需要被GC,即對象是否存活判定算法。
判定對象存活算法
如何判斷對象淪為了垃圾也是門技術。
引用計數法
引用計數法就是給對象加個引用計數器,每有一個地方引用到它時,這個引用計數器就加1。當引用失效的時候,計數器的值就減1,也就是說根據引用計數器的值來判斷對象是否存活,若值是0,那麼該對象就不再被使用了。
真是如此嗎?答案是否定的。試想一下如下圖的場景:
AB對象互相引用,那麼AB對象的引用計數器的值永遠都不會為0,AB就永遠都不會被回收,直接造成記憶體洩漏問題。是以該算法最大的缺點是
很難解決對象之間互相引用的問題
。但事實上,如上圖情況的互相引用對象會被回收,說明實際不是用引用計數法判定對象存活與否。
可達性分析法
可達性分析法的基本思路是通過一系列的GC Roots對象作為起始點,從這些點向下搜尋它們引用的對象,這樣可以生成一顆引用樹,樹的節點就是可達的對象。反之,不在樹上的對象即可判定對象已死。來看如下圖:
D和E對象互相引用,但是它們沒有RC Roots根節點的引用指向,是以D和E在下次垃圾回收時會被處死,而ABC對象在GC Roots的引用樹上,會視為存活對象。
那麼哪些對象可以作為引用樹的根節點呢?
可作為GC Roots的對象
不難想象,作為GC Roots的對象必須是極難被回收的對象,包括了如下幾種對象:
- 虛拟機棧(
)中引用的對象,如在方法中定義和使用的變量棧幀中的本地變量表
- 方法區中的
,如static修飾的成員變量類靜态屬性引用的對象
- 方法區中
,如static和final共同修飾的常量常量引用的對象
- 本地方法棧中
,JNI也就是調的native方法JNI引用的對象
引用類型與垃圾回收時機
不論是通過以上哪種方式判斷對象是否存活,都與
引用
相關。java自1.2之後,對引用劃分了4種,如下:
-
:隻要某個對象有強引用與之關聯,JVM必定不會回收這個對象,即使在記憶體不足的情況下,強引用
這種對象。JVM甯願抛出OutOfMemory錯誤也不會回收
-
:軟引用是用來描述一些有用但并不是必需的對象,比如引用圖檔位址等,在Java中用java.lang.ref.SoftReference類來表示。對于軟引用關聯着的對象,軟引用
該對象。隻有在記憶體不足的時候JVM才會回收
-
:弱引用也是用來描述非必需對象的,當JVM進行垃圾回收時,無論記憶體是否充足,都會回收被弱引用關聯的對象。也就是說被弱引用關聯的對象,弱引用
。隻能生存到下一次垃圾收集發生之前
-
:虛引用和前面的軟引用、弱引用不同,它并不影響對象的生命周期。在java中用java.lang.ref.PhantomReference類表示。如果一個對象與虛引用關聯,則跟沒有引用與之關聯一樣,在任何時候都可能被垃圾回收器回收。為一個對象設定虛引用關聯的虛引用(幽靈引用或幻影引用)
。與弱引用差別:在GC時會被通知。唯一目的就是能在這個對象被收集器回收時收到一個系統通知
好了,今天點到為止,下篇談談垃圾回收算法和垃圾回收器。