弱引用对象不会被垃圾收集
Weakly referenced object won't get garbage collected
我担心的是某个对象的实例曾经被强引用,但是在对其强引用进行显式空赋值和显式 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 生态系统中有多种垃圾收集器的实现,它们的行为截然不同。
何时进行垃圾收集 运行s 因垃圾收集器的实现而异,也可能取决于 JVM 的当前状况。一个收集器可能 运行 几乎持续不断,而另一个收集器可能会一直等到内存不足。 (为了表达清楚,我在这里过于简单化了。)
是收集所有垃圾,还是只收集其中的一部分,也可能因收集器实现和 JVM 的状态而异。
调用System.gc
只是一个建议,不是命令。垃圾收集器可以随意忽略它。
在 Java 中,您不应该在管理内存方面花费太多精力。现代 JVM 实现在这方面比任何单个程序员都可能做得更好。只需确保在使用完对象后释放对对象的所有引用。或者使用 WeakReference
/SoftReference
。然后信任 JVM 和垃圾收集器来完成它的工作。
在极端情况下(非常大的内存,或大量的对象流失),您可能想要研究各种垃圾收集器实现的行为。也许可以考虑替代方案,例如来自 Azul Systems 的 Zing 或来自 Oracle 的 GraalVM。但对于大多数项目,通常基于 OpenJDK 的 JVM 工作得很好。
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
或者,不要使用局部变量创建强引用,直接从弱引用调用方法即可。这样你就不会像以前那样不小心留下强引用。 *(在 printA()
调用期间,this
引用是强引用,因此在 调用期间 不能对对象进行 GC)*
Example strongReferenceWrappedInWeak = new Example(42);
strongReferenceWrappedInWeak.printA();
WeakReference<Example> exampleWeakReference = new WeakReference<>(strongReferenceWrappedInWeak);
System.gc(); //does not collect object, since strong reference still exists
exampleWeakReference.get().printA(); //works
strongReferenceWrappedInWeak = null; //eligible for garbage collection
System.gc(); //collects object, since it is now weakly referenced only
exampleWeakReference.get().printA(); //throws NPE
输出(来自两者)
42
42
Exception in thread "main" java.lang.NullPointerException
at Test.main(Test.java:**)
测试于 Java 13
我担心的是某个对象的实例曾经被强引用,但是在对其强引用进行显式空赋值和显式 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 生态系统中有多种垃圾收集器的实现,它们的行为截然不同。
何时进行垃圾收集 运行s 因垃圾收集器的实现而异,也可能取决于 JVM 的当前状况。一个收集器可能 运行 几乎持续不断,而另一个收集器可能会一直等到内存不足。 (为了表达清楚,我在这里过于简单化了。)
是收集所有垃圾,还是只收集其中的一部分,也可能因收集器实现和 JVM 的状态而异。
调用System.gc
只是一个建议,不是命令。垃圾收集器可以随意忽略它。
在 Java 中,您不应该在管理内存方面花费太多精力。现代 JVM 实现在这方面比任何单个程序员都可能做得更好。只需确保在使用完对象后释放对对象的所有引用。或者使用 WeakReference
/SoftReference
。然后信任 JVM 和垃圾收集器来完成它的工作。
在极端情况下(非常大的内存,或大量的对象流失),您可能想要研究各种垃圾收集器实现的行为。也许可以考虑替代方案,例如来自 Azul Systems 的 Zing 或来自 Oracle 的 GraalVM。但对于大多数项目,通常基于 OpenJDK 的 JVM 工作得很好。
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
或者,不要使用局部变量创建强引用,直接从弱引用调用方法即可。这样你就不会像以前那样不小心留下强引用。 *(在 printA()
调用期间,this
引用是强引用,因此在 调用期间 不能对对象进行 GC)*
Example strongReferenceWrappedInWeak = new Example(42);
strongReferenceWrappedInWeak.printA();
WeakReference<Example> exampleWeakReference = new WeakReference<>(strongReferenceWrappedInWeak);
System.gc(); //does not collect object, since strong reference still exists
exampleWeakReference.get().printA(); //works
strongReferenceWrappedInWeak = null; //eligible for garbage collection
System.gc(); //collects object, since it is now weakly referenced only
exampleWeakReference.get().printA(); //throws NPE
输出(来自两者)
42
42
Exception in thread "main" java.lang.NullPointerException
at Test.main(Test.java:**)
测试于 Java 13