大家下午好,爲什麼我的變量不能超出範圍?
我被告知當一個函數返回時,變量(在該函數的範圍內)自動超出範圍,所以我們不必將它們設置爲null。
但是,這似乎並不正確。
我有一個測試代碼,創建一個指向java.lang.Object的實例的java.lang.ref.PhantomReference。對該對象的唯一強引用在函數F的範圍內。
換句話說,當該函數返回時,應該不再有任何對該對象的強引用,並且該對象現在應該可由GC。
但是,無論我多麼努力地試圖讓內存的JVM捱餓,GC只是拒絕收集對象。令人驚訝的是,如果我將該變量設置爲空(obj = null;
),則GC現在收集該對象。
這種古怪背後的解釋是什麼?符合標準的
public class Test {
public static void main(String args[]) {
// currently testing on a 64-bit HotSpot Server VM, but the other JVMs should probably have the same behavior for this use case
Test test = new Test();
test.F(new Object());
}
public <T> void F(T obj) {
java.lang.ref.ReferenceQueue<T> ref_queue = new java.lang.ref.ReferenceQueue<T>();
java.lang.ref.PhantomReference<T> ref = new java.lang.ref.PhantomReference<T>(obj, ref_queue); // if this line isn't an assignment, the GC wouldn't collect the object no matter how hard I force it to
obj = null; // if this line is removed, the GC wouldn't collect the object no matter how hard I force it to
StartPollingRef(ref_queue);
GoOom();
}
private <T> void StartPollingRef(final java.lang.ref.ReferenceQueue<T> ref_queue) {
new java.lang.Thread(new java.lang.Runnable() {
@Override
public void run() {
System.out.println("Removing..");
boolean removed = false;
while (!removed) {
try {
ref_queue.remove();
removed = true;
System.out.println("Removed.");
} catch (InterruptedException e) { // ignore
}
}
}
}).start();
}
private void GoOom() {
try {
int len = (int) java.lang.Math.min(java.lang.Integer.MAX_VALUE, Runtime.getRuntime().maxMemory());
Object[] arr = new Object[len];
} catch (Throwable e) {
// System.out.println(e);
}
}
}
這使得析構函數在語言設計錯誤發生時是一個完整的錯誤。 – tchrist 2012-02-25 01:33:27
@Borealid然而,不是java.lang.ref.PhantomReference的全部內容,只要對象離開堆,我們都可以得到通知。不會*傲慢*(缺乏更好的詞)JVM渲染整個類無用嗎? – Pacerier 2012-02-25 01:37:37
+1,並且爲了澄清,當GC確定它可以被GCC化時,通常將弱參考排入隊列,而當GC進行下一步並且實際GC時,虛擬參考被排隊。這有點模糊,並不完全準確;請參閱[這裏](http://docs.oracle.com/javase/6/docs/api/java/lang/ref/package-summary.html#reachability)以獲得更準確的定義。 – yshavit 2012-02-25 01:38:15