垃圾收集器如何判斷內(nèi)存是否需要回收
java的內(nèi)存分配有:程序計數(shù)器、虛擬機棧、本地方法棧、java堆、方法區(qū)
其中程序計數(shù)器、虛擬機棧、本地方法棧隨著線程而生、線程而死,而內(nèi)存的分配在類結構確定下來就已經(jīng)確定了,在內(nèi)存大小和回收時機上是確定的。而java堆和方法區(qū)就比較麻煩,我們只有在程序運行時,才知道要分配多大的空間,而什么時候創(chuàng)建和回收也是不確定的。
回收策略
引用計數(shù)法
給對象添加一個引用計數(shù)器,每當有一個地方引用它,就給計數(shù)器+1;引用失效,計數(shù)器-1,當引用技術器為0時就判定對象可以回收。
可達性分析
引用計數(shù)法是不靠譜的,如果兩個對象中各有一個字段引用對方對象,而對象本身卻已經(jīng)不可能再被訪問了,可是引用計數(shù)法都不為0,在這種情況下GC回收器還是會回收內(nèi)存的。代碼如下:
public class ReferenceCountingGC {
public Object instance = null;
public static void main(String[] args) throws Exception {
ReferenceCountingGC objA = new ReferenceCountingGC();
ReferenceCountingGC objB = new ReferenceCountingGC();
objA.instance = objB;
objB.instance = objA;
objA = null;
objB = null;
System.gc();
}
}
所以在java語言中并沒有采用引用技術法作為回收策略,使用了可達性分析算法。
可達性分析算法中,定義了一種名為“GC Root”的對象,對象之間的引用構成圖,凡是被“GC Root”為起點,走過的路徑稱為引用鏈,引用鏈上的對象不會被回收。
哪些是“GC Root”對象呢?
- 虛擬機棧(本地變量表)中引用的對象。
- 方法區(qū)中類的靜態(tài)變量引用的對象。
- 方法區(qū)中常量引用的對象。
- 本地方法棧中引用的對象。
回收方法區(qū)
上面說到的對象回收是發(fā)生在java堆中,而方法區(qū)也是有回收垃圾的,主要回收廢棄常量和無用的類。