web-dev-qa-db-fra.com

Utiliser la ReferenceQueue de Java

Est-ce que SoftReference et WeakReference n'aident vraiment que lorsqu'ils sont créés en tant que variables d'instance? Y a-t-il un avantage à les utiliser dans le champ d'application de la méthode?

L'autre grande partie est ReferenceQueue. En plus de pouvoir suivre quelles références sont déterminées garbage, Reference.enqueue() peut-il être utilisé pour enregistrer de manière forcée un objet pour le garbage collection?

Par exemple, cela vaudrait-il la peine de créer une méthode qui utilise des ressources de mémoire lourdes (détenues par des références fortes) dans un objet et de créer des références pour les mettre en file d'attente?

Object bigObject;
public void dispose() {
    ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
    WeakReference<Object> ref = new WeakReference<Object>(bigObject, queue);
    bigObject = null;
    ref.enqueue();
}

(Imaginez que Object dans ce cas représente un type d'objet qui utilise beaucoup de mémoire ... comme BufferedImage ou quelque chose)

Cela at-il un effet réaliste? Ou est-ce juste une perte de code?

22
bgroenks

Un idiome courant avec des files d'attente de référence est par exemple: sous-classe WeakReference pour joindre les informations nécessaires au nettoyage, puis interroger une ReferenceQueue pour obtenir des tâches de nettoyage.

ReferenceQueue<Foo> fooQueue = new ReferenceQueue<Foo>();

class ReferenceWithCleanup extends WeakReference<Foo> {
  Bar bar;
  ReferenceWithCleanup(Foo foo, Bar bar) {
    super(foo, fooQueue);
    this.bar = bar;
  }
  public void cleanUp() {
    bar.cleanUp();
  }
}

public Thread cleanupThread = new Thread() {
  public void run() {
    while(true) {
      ReferenceWithCleanup ref = (ReferenceWithCleanup)fooQueue.remove();
      ref.cleanUp();
    }
  }
}

public void doStuff() {
  cleanupThread.start();
  Foo foo = new Foo();
  Bar bar = new Bar();
  ReferenceWithCleanup ref = new ReferenceWithCleanup(foo, bar);
  ... // From now on, once you release all non-weak references to foo,
      // then at some indeterminate point in the future, bar.cleanUp() will
      // be run. You can force it by calling ref.enqueue().
}

Par exemple, les éléments internes de la CacheBuilder implémentation de Guava lorsque weakKeys sont sélectionnés utilise cette approche.

31
Louis Wasserman

Si un objet ne contient que WeakReferences (ou aucune référence!), Il peut être nettoyé à la poubelle chaque fois que Java doit libérer de la place dans la mémoire. Donc, vous utilisez WeakReferences chaque fois que vous voulez qu'un objet reste en mémoire, mais vous n'en avez pas besoin pour rester CELA mal (par exemple, si Java doit le ramasser, pas de problème, vous pouvez le récupérer d'une manière ou d'une autre). Java a de meilleures performances)

Mettre en attente une WeakReference vous permet d'itérer la ReferenceQueue et de déterminer quelles références ont été collectées et celles qui ne l'ont pas été. C'est tout, alors ne le faites que si vous avez besoin de le savoir.

En savoir plus: http://weblogs.Java.net/blog/2006/05/04/understanding-weak-references

5
Patashu

Une chose commune à faire est de créer des cartes de références logicielles.

Map<String, SoftReference<BigThing>> cache = new HashMap<>();
Set<String> thingsIAmCurrentlyGetting = new HashSet<String>();
Object mutex = new Object();

BigThing getThing(String key) {
  synchronized(mutex) {
    while(thingsIAmCurrentlyGetting.contains(key)) {
      mutex.wait();
    }
    SoftReference<BigThing> ref = cache.get(key);
    BigThing bigThing = ref == null ? null : ref.get();
    if(bigThing != null) return bigThing;
    thingsIAmCurrentlyGetting.add(key);
  }

  BigThing bigThing = getBigThing(key); // this may take a while to run.

  synchronized(mutex) {
    cache.put(key, bigThing);
    thingsIAmCurrentlyGetting.remove(key);
    mutex.notifyAll();
  }

  return bigThing;
}

Je montre ici mon ancienne école - les nouveaux packages Java ont probablement des moyens beaucoup plus astucieux de le faire.

4
PaulMurrayCbr

Je ne sais pas quelle est la question ici mais:

1) soft ref essayez de garder la référence jusqu'à ce que jvm ait vraiment besoin de mémoire. Idéal pour les caches, surtout les LRU. Regardez de nombreux exemples en goyave.

2) faible ref n'essayez pas d'empêcher gc de libérer l'objet du tout. Ils sont utilisés si vous voulez savoir si cet objet est encore utilisé quelque part. Par exemple, ils sont utilisés pour stocker des informations sur les threads et les classes, de sorte que lorsque le thread ou la classe n'est plus utilisé, nous pouvons écarter le metainfo associé à cela.

3) les références fantômes sont comme faibles, mais sans vous permettre de référencer l’objet réel. De cette façon, vous pouvez être sûr que le fait de passer avec le fantôme ne peut pas reprendre l'objet réel (c'est un risque avec un faible ref). De plus, les références fantômes bloquent l'objet à collecter jusqu'à ce que vous effaciez la référence.

ReferenceQueue: vous n'écrivez rien. gc fera pour vous. Ils vous permettent de savoir quand certaines références sont publiées, sans avoir à les vérifier une à une.

1
Uberto