自動垃圾回收是Java相較於C++的一個重要的特點,想了解JVM的垃圾回收機制,首先我們要知道垃圾回收是回收什麼地方的垃圾,我在我的上一篇文章《JVM內存區域劃分》裡面有寫到JVM裡面的內存是怎麼分布的,這裡的回收主要是指對上文中提到的Java堆和方法區的內存的回收。
知道了回收哪裡的內存之後,我們還需要知道什麼樣的對象是可以被回收,或者說是需要被回收的,這些對象我們稱之為死掉的對象。那麼哪些對象是死掉了的呢?我們說當一個對象不存在任何引用的時候就可以說這個對象是死掉了。
那麼什麼時候這個對象不存在任何引用了呢?
有一些地方說,可以使用引用計數算法來判斷對象是否還存活,引用計數算法是說給對象添加一個引用計數器,每當一個地方引用它時就加1,引用失效時就減1,計數器的值變為0就說這個對象不存在任何引用了,但是這樣會存在一個很嚴重的問題,就是循環引用的問題。比如如下的例子:
public class Example{
public Object instance = null;
publicstaticvoidtest(){
Example objA=new Example();
Example objB=new Example();
objA.instance=objB;
objB.instance=objA;
objA=null;
objB=null;
}
}
這樣的話,objA和objB的引用計數都不為0,但是他們的確是不會再被使用的了。
那麼Java裡面是用什麼樣的算法來實現對引用的判斷的呢?
Java裡是使用可達性分析的方法來實現的。
如圖所示,就是通過一系列的稱為"GC Roots"的對象作為起始點,從這些點向下搜索,搜索的路徑稱為引用鏈,當一個對象到達GC Roots沒有任何引用鏈時,就可以證明這個對象是不可用的。那麼這個對象就可以被回收了。像圖中的Obj1-5都屬於存活的對象,但是Obj6-8雖然還存在相互引用,但是已經是可以認為是死掉的對象了。
目前來說,Java中的引用可以分為強引用(Strong Reference)、軟引用(Soft Reference)、弱引用(Weak Reference)、虛引用(Phantom Reference)四種,他們的引用順序依次逐漸減弱。
當一個對象在進行可達性分析的時候發現已經是沒有任何引用的了,這時候垃圾收集器並沒有立即判處該對象死刑,而是給了它一次自我救贖的機會,這時它會被標記一次,同時判斷是不是有必要執行finalize()方法,當對象沒有重寫finalize()方法或者finalize()方法已經被執行過的時候,就不執行finalize()方法。下面就會有兩種情況發生了:
方法區的回收分為廢棄常量的回收和無用類的卸載。