[英]Why is only 1 object eligible ready for GC?
當到達包含“//doStuff”的行時,有多少對象可用於垃圾回收?
a. 0
b. 1
c. 2
d. 3
e. 4
f. 5
class Beta
{
}
class Alpha
{
static Beta b1;
Beta b2;
}
public class Tester
{
public static void main(String[] args)
{
Alpha a1=new Alpha();
Alpha a2=new Alpha();
Beta b1= new Beta();
Beta b2= new Beta();
a1.b1=b1;
a1.b2=b1;
a2.b2=b2;
a1=null;
b1=null;
b2=null;
//doStuff
}
}
給出答案:1
我認為答案應該是 2,因為分配給 a1 和 b1 的對象不再可訪問。
像這樣的問題很少有任何意義。 通常,提問者(面試官)會在問題中加入一個特定的陷阱,並會考慮任何確定問題的正確答案,而忽略問題的其他內在缺陷。
在這里,問題是分配a1.b1=b1;
分配給一個static
字段,即使a1
被分配給null
,它也會使引用保持活動狀態。
“有多少對象可用於垃圾收集?”這個問題的根本缺陷。 是我們甚至不知道,有多少對象存在。 JVM 初始化和啟動器啟動代碼可能已經創建了任意數量的臨時對象,當進入main
方法時可以進行垃圾回收,並且在到達指定點時仍然可以進行垃圾回收。
即使我們將問題限制在問題代碼中可見的工件,給出的答案也是錯誤的。
Java® 語言規范指出:
可達對象是可以從任何活動線程在任何潛在的持續計算中訪問的任何對象。
雖然沒有指向對象的引用圖是一個明確且易於測試的對象無法訪問的證明,但存在這樣的引用並不一定意味着“潛在的持續計算”實際上會訪問它。 這更難測試,但實現是否真的這樣做並不影響對象是否正式“符合垃圾收集條件” * 。
該規范甚至明確指出:
可以設計優化程序的轉換,將可達的對象數量減少到比天真地認為可達的對象數量更少。 例如,Java 編譯器或代碼生成器可能會選擇將不再用於
null
的變量或參數設置為null
從而使此類對象的存儲可能更快地被回收。
我們有一個未使用的參數args
,這里指向一個字符串數組,可以進行垃圾回收。 事實上,在這個例子中,數組可能指向任意數量的符合垃圾回收條件的字符串,這再次導致可回收對象的數量未知的結論。
這同樣適用於局部變量a2
。 只要隨后不使用它,它就不會阻止所指對象(以及a2.b2
引用的Beta
實例)進行垃圾回收。
另請參閱當對象仍在范圍內時,java 是否可以完成它? 關於這個主題, finalize() 調用了 Java 8 中的強可達對象,以解決由關於垃圾收集的幼稚假設引起的現實生活問題。
不過,這些都是關於可觀察到的行為。 在問題的代碼中, Alpha
和Beta
都沒有finalize()
方法可以使其實例的集合可觀察,因此原則上,JVM 可以回收所有對象的內存,包括static
字段引用的對象,而不會引起任何人的注意.
*一件事,這些問題很少說,是他們談論的是理論還是實踐。 形式上,有資格進行垃圾回收的對象遠多於實現實際識別的對象。 識別未使用變量的能力可能取決於優化狀態,而簡短的main
方法很少得到優化。 另一方面,垃圾收集器通常甚至不會運行這么短的執行時間,而是 JVM 會整體釋放整個堆。
所以理論上,幾乎所有的對象都有資格進行垃圾回收,而在實踐中,根本沒有被回收。 因此,兩種觀點都不會導致數字,提問者想聽到......
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.