Java中GCRoots包括哪些
在垃圾回收過程中如何判斷一個對象是否是垃圾,有兩種算法。一種是引用記數法,一種是可達性分析法。
- 引用記數法是早期垃圾回收器中使用的算法,每一個對象維護一個該對象被引用的記數,每引用一次,記數加1,每減少引用1次,引用減1,當引用為0時,表示該對象不再被引用,可以作為垃圾被清除。但是引用記數法有一個最致命的問題,就是無法解決循環引用的問題。
- 可達性分析法,是通過從GCRoots出發,找出內存中的引用鏈,那么鏈中的對象表示可達,即不能作為被垃圾回收的。引用鏈之外的對象即可作為垃圾回收。Java中使用的是可達性分析法。
所以在可達性分析法中,判斷哪些引用是GCRoots是垃圾回收的起點,那么這篇文章,就說說哪些引用是GCRoots。
GCRoots
- 虛擬機棧(棧幀中的本地變量表)中引用的對象
- 方法區中類靜態屬性引用的對象,(一般指被static修飾的對象,加載類的時候就加載到內存中。)
- 方法區中常量引用的對象
- 本地方法棧中JNI(即一般說的native方法)中引用的對象
比如下面的代碼:
其中,類靜態變量 MAPPER,loadAccount 方法的局部變量 account1、account2、accountList 都可以作為 GC Roots(ArrayList 內部是用 Object[] elementData 數組來存放元素的)。
在調用 loadAccount 方法時,堆中的對象都是可達的,因為有 GC Roots 直接或間接引用到這些對象,此時若發生垃圾回收,這些對象是不可被回收的。loadAccount 執行完后,彈出棧幀,方法內的局部變量都被回收了,雖然堆中 ArrayList 對象還指向 elementData 數組,而 elementData 指向 Account 對象,但沒有任何 GC Roots 的引用鏈能達到這些對象,因此這些對象將變為垃圾對象,被垃圾回收器回收掉。