[我担心的是曾经被强引用的对象的实例,但是在对其强引用进行显式的空赋值之后,以及在显式的System.gc()
调用之后,仍可以通过弱引用访问该实例。如果我理解正确,当所引用的对象仅剩下弱引用时,可以确保在下一个GC会话中清除该引用。我想念什么?
参考代码:
public class References {
public static void main(String[] args) {
Example strongReferenceWrappedInWeak = new Example(42);
strongReferenceWrappedInWeak.printA();
WeakReference<Example> exampleWeakReference = new WeakReference<>(strongReferenceWrappedInWeak);
System.gc();
Example retrievedExample = exampleWeakReference.get();
retrievedExample.printA(); //this works, because a strong reference is present to the instance, hence it's not cleared
strongReferenceWrappedInWeak = null; //eligible for garbage collection
System.gc();
Example retrievedExampleTwo = exampleWeakReference.get(); //should be null
retrievedExampleTwo.printA(); //should throw NPE
}
}
class Example {
private int a;
Example(int a) {
this.a = a;
}
void printA() {
System.out.println(this.a);
}
}
垃圾收集的工作方式很神秘。
Java生态系统中有几种垃圾收集器的实现,它们的行为非常不同。
何时运行垃圾回收取决于垃圾回收器的实现,并且还可能取决于JVM的当前条件。一个收集器可能几乎连续运行,而另一个收集器可能要等到内存不足时才运行。 (我在这里简化太多,以使观点更清楚。)
无论是收集所有垃圾还是仅收集其中的一部分,都可能因收集器实现和JVM状态而异。
对System.gc
的调用只是一个建议,而不是命令。垃圾收集器可以随意忽略它。
在Java中,您不应该在管理内存上付出很大的努力。现代的JVM实现远胜于任何单个程序员。只要确保在使用完对象后释放它们的所有引用即可。或使用System.gc
/ WeakReference
。然后信任JVM和垃圾收集器来完成其工作。
在极端情况下(非常大的内存或大量的对象搅动),您可能需要研究各种垃圾收集器实现的行为。也许可以考虑使用替代方案,例如Azul Systems的Zing或Oracle的GraalVM。但是对于大多数项目,通常基于OpenJDK的JVM都可以很好地工作。
[SoftReference
不会使strongReferenceWrappedInWeak = null
对象实例具有进行垃圾回收的资格,因为Example
仍然对其具有很强的引用性。。
要解决,请添加retrievedExample
retrievedExample = null;
输出
Example strongReferenceWrappedInWeak = new Example(42);
strongReferenceWrappedInWeak.printA();
WeakReference<Example> exampleWeakReference = new WeakReference<>(strongReferenceWrappedInWeak);
System.gc();
Example retrievedExample = exampleWeakReference.get();
retrievedExample.printA(); //this works, because a strong reference is present to the instance, hence it's not cleared
retrievedExample = null;
strongReferenceWrappedInWeak = null; //now eligible for garbage collection
System.gc();
Example retrievedExampleTwo = exampleWeakReference.get(); //will be null
retrievedExampleTwo.printA(); //will throw NPE
Java 13上测试