Java-WeakReference最佳实践

Java-WeakReference最佳实践,java,garbage-collection,weak-references,Java,Garbage Collection,Weak References,在回答这个问题之前,我会说我是Java垃圾收集新手,所以如果收集器解决了这个问题,我会很高兴的。或者,如果我对Java内存分配一无所知(事实上是如此),我道歉。但是,我正在考虑以下三种情况: public class ScenarioA implements MyQuestion{ private Field field; public Field getField(){ if(field == null){ field = new Fi

在回答这个问题之前,我会说我是Java垃圾收集新手,所以如果收集器解决了这个问题,我会很高兴的。或者,如果我对Java内存分配一无所知(事实上是如此),我道歉。但是,我正在考虑以下三种情况:

public class ScenarioA implements MyQuestion{

    private Field field;

    public Field getField(){
        if(field == null){
           field = new Field(this);
        }
        return field;
}
vs

vs

import java.lang.ref.WeakReference;
公共类场景IoC实现MyQuestion{
私人WeakReference weakField;
公共字段getField(){
if(WeakField==null | | WeakField.get()==null){
weakField=新WeakReference(新字段(this));
}
返回weakField.get();
}
}
我认为
ScenarioA
很糟糕,因为如果对
ScenarioA
的实例调用
.get()
,我们将在
ScenarioA
的实例和
.get()
方法返回的
字段的实例之间维护强引用,这意味着无论程序是否真正关心其中任何一个,它们都不会被垃圾收集

ScenarioB
有可能实例化大量的
.equal
对象的问题,这可能非常昂贵且不必要

ScebarioC
我至少懂一点。我试图阅读
WeakReference
()的源代码,但我不知道发生了什么。我想把这归咎于幕后发生的某些GC/VM操作,但我想把很多事情归咎于其他很多事情。无论如何,在我看来,每个
WeakReference
都必须严格要求比简单地维护对引用对象的引用更多的内存,因为我们必须首先维护对
WeakReference
的引用,然后维护对实际对象的引用。(我为那句话道歉)。如果
字段
很大,并且/或者我们实例化了几个
场景
,这可能会很糟糕。但更重要的是,在我看来,每个
WeakReference
都需要它自己的线程,除非实例
ScenarioC
——因此弱引用——消亡,否则线程本身(线程)似乎永远不会消亡。如果存在大量的
ScenarioC
实例,这可能会非常糟糕


有人能解决这个问题吗?

对于
WeakReference
的最佳实践,我唯一的建议是不要使用它们,除非你真的必须。他们不会帮你做你想做的事

您似乎担心生成太多对象—这是Java新手的常见错误。生成对象并释放它们是Java中的一个基本机制,并且已经被调整为非常高效。您需要考虑的唯一问题是对象是否需要花费大量时间来构建或占用大量空间。在这种情况下,你应该考虑使用一个池(它可以在幕后使用<代码> WeakReference < /代码>)。

另一种可供选择的方法是使用<代码> Stutelon .< /P> < p>您不能通过查看其源代码来获得<代码> WeakReference < /C> >的工作方式。垃圾收集器知道

WeakReference
类的特殊语义,并相应地处理其
引用对象。当您确实需要使用
WeakReference
时,您必须意识到,只要没有对其
引用对象的普通(也称为强)引用,其
get
方法始终可以返回
null
,即使您只是在其前面检查了
get
的返回值,即使您刚刚在它前面创建了
WeakReference

必须使用强引用(例如在局部变量中)来保存新实例或在返回前检查由
WeakReference.get()
返回的实例:

import java.lang.ref.WeakReference;

public class ScenarioC implements MyQuestion {

    private WeakReference<Field> weakField;

    public Field getField() {
      if(weakField!=null) {
        Field field = weakField.get(); // create an ordinary strong reference
        if(field!=null) return field; // the strong reference works as known
      }
      Field field=new Field(this); // keep the new instance ordinarily
      weakField = new WeakReference<Field>(field);
      return field; // return the ordinary strong reference to the new instance
    }
}
import java.lang.ref.WeakReference;
公共类场景实现MyQuestion{
私人WeakReference weakField;
公共字段getField(){
如果(weakField!=null){
Field=weakField.get();//创建一个普通的强引用
if(field!=null)返回字段;//强引用按已知方式工作
}
Field=new Field(this);//通常保留新实例
weakField=新WeakReference(字段);
返回字段;//返回对新实例的普通强引用
}
}

请注意,此代码仍然不是线程安全的,它仅显示在考虑使用
WeakReference
时如何处理可能的垃圾收集,你应该扪心自问,如果在没有对目标的有力引用时,它们立即失效,你会有什么感觉。在
WeakReference
合适的大多数地方,这样的行为是可取的;如果这种行为在特定情况下是不受欢迎的,那么这通常表明其他形式的缓存更合适

基本上,
WeakReference
通常不适合建立与目标对象本身的连接,而是用于建立与引用目标对象的其他对象的间接连接。当没有其他东西引用目标对象时,弱引用将变得无用,应该消除

例如,考虑一个object
Joe
,其目的是让感兴趣的人知道object
Fred
做某事的次数。它要求
Fred
让它知道(通过调用一个方法)每当它执行有问题的操作时,每次调用该方法时,都会增加一个计数器。在这种情况下,弗雷德要么对乔持有弱引用,要么对持有弱引用的东西持有引用,这是合适的
import java.lang.ref.WeakReference;

public class ScenearioC implements MyQuestion{

    private WeakReference<Field> weakField;

    public Field getField(){
        if(WeakField == null || weakField.get() == null){
            weakField = new WeakReference(new Field(this));
        }
        return weakField.get();
    }
}
import java.lang.ref.WeakReference;

public class ScenarioC implements MyQuestion {

    private WeakReference<Field> weakField;

    public Field getField() {
      if(weakField!=null) {
        Field field = weakField.get(); // create an ordinary strong reference
        if(field!=null) return field; // the strong reference works as known
      }
      Field field=new Field(this); // keep the new instance ordinarily
      weakField = new WeakReference<Field>(field);
      return field; // return the ordinary strong reference to the new instance
    }
}