[英]Java WeakReference GC finalized , not finalized?
我以為 WeakReference 參考 object 將在 System.gc() 調用后完成,但我錯了。
這里有兩個測試用例,唯一的區別是 WeakReference 構造函數,第一個是新的 object 而第二個使用的是引用,它們有不同的性能,我不知道為什么......
弱引用對象,不會阻止它們的引用對象被最終化、最終化,然后被回收。 弱引用最常用於實現規范化映射。
假設垃圾收集器在某個時間點確定 object 是弱可達的。 屆時,它將自動清除對 object 的所有弱引用以及對任何其他弱可達對象的所有弱引用,通過強引用和軟引用鏈可以從這些弱可達對象中訪問 object。 同時它將聲明所有以前的弱可達對象都是可終結的。 在同一時間或稍后的某個時間,它會將那些在引用隊列中注冊的新清除的弱引用排入隊列。
package com.zeng.javaReference;
import org.junit.Test;
import java.lang.ref.WeakReference;
/**
* @author zeng
* @version 1.0.0
* @date 2020-05-11
*/
public class WeakReferenceTest {
@Test
public void weakRefRemoved() {
WeakReference<Apple> weakReference = new WeakReference<>(new Apple("green-apple"));
System.gc();
if (weakReference.get() == null) {
System.out.println("GC remove weakReference!");
} else {
System.out.println("weakReference still alive");
}
}
@Test
public void weakRefNotRemoved() {
Apple apple = new Apple("green-apple");
WeakReference<Apple> weakReference = new WeakReference<>(apple);
System.gc();
if (weakReference.get() == null) {
System.out.println("GC remove weakReference!");
} else {
System.out.println("weakReference still alive");
}
}
public static class Apple {
private String name;
public Apple(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("Apple: " + name + " finalized。");
}
@Override
public String toString() {
return "Apple{" +
"name='" + name + '\'' +
'}' + ", hashCode:" + this.hashCode();
}
}
}
System.gc()
可能會也可能不會觸發垃圾收集。
通過手動調用它,您只是在向 JVM 提供提示,但它是否會兌現它完全取決於 java 運行時。 JVM 是非常復雜的系統,不允許直接訪問資源。
至於文檔中的WeakReference
弱參考是指其強度不足以使 object 保留在 memory 中的參考。 因此,弱引用可以讓垃圾收集器決定對象的可達性,以及是否應該將有問題的 object 保留在 memory 中。
再次決定收集 object 的天氣完全取決於收集器。
這確實是相當有趣的。
假設您使用的 GC 收集器在調用System.gc()
時實際執行了某些操作,例如G1
,並且您沒有通過-XX:+DisableExplicitGC
禁用對 GC 的顯式調用,則不知何故對此有解釋。
理論上, weakRefNotRemoved
應該與weakRefRemoved
一樣工作。 這與scope
和reachability
有關, 這里有更多詳細信息。
關鍵是在weakRefNotRemoved
中,調用System.gc()
之后的apple
引用沒有被任何人使用,所以在那個時候它是不可訪問的。 因此,理論上,GC 可以回收它,但無論出於何種原因,它都不會。 我只能假設這個特殊路徑只有在有真正的 memory 壓力時才會觸發。
為了證明這一點,我們可以稍微修改一下代碼,如下:
public static void weakRefNotRemoved() {
Apple apple = new Apple("green-apple");
WeakReference<Apple> weakReference = new WeakReference<>(apple);
// explicitly set to null
apple = null;
System.gc();
if (weakReference.get() == null) {
System.out.println("GC remove weakReference!");
} else {
System.out.println("weakReference still alive");
}
}
現在,GC 確實會清理它。 一般來說,如果你試圖證明一個觀點,最好在 while 循環下調用它,因為不能保證循環會“捕獲” 那個引用。 也因為清除以異步方式發生。 就像是:
public static void weakRefNotRemoved() {
Apple apple = new Apple("green-apple");
WeakReference<Apple> weakReference = new WeakReference<>(apple);
apple = null;
while (weakReference.get() != null) {
System.out.println("weakReference still alive");
System.gc();
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));
}
System.out.println("GC remove weakReference!");
}
而且得到這樣一個output是完全合法的,例如:
weakReference still alive // zero or more of these messages
GC remove weakReference!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.