web-dev-qa-db-ja.com

JavaのReferenceQueueの使用

SoftReferenceWeakReferenceは、インスタンス変数として作成された場合にのみ本当に役立ちますか?それらをメソッドスコープで使用するメリットはありますか?

もう1つの大きな部分はReferenceQueueです。ガベージと判断された参照を追跡できるだけでなく、ガベージコレクションのオブジェクトを強制的に登録するためにReference.enqueue()を使用できますか?

たとえば、オブジェクト内で(強い参照によって保持されている)重いメモリリソースを受け取り、それらをエンキューするための参照を作成するメソッドを作成する価値はありますか?

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

(この場合のオブジェクトが、BufferedImageなどの多くのメモリを使用するオブジェクトタイプを表すと想像してください)

これには現実的な効果がありますか?または、これは単なるコードの無駄ですか?

24
bgroenks

参照キューの一般的なイディオムの1つは、 WeakReferenceをサブクラス化して、クリーンアップに必要な情報を添付し、ReferenceQueueをポーリングしてクリーンアップタスクを取得します。

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().
}

たとえば、CacheBuilderが選択されているときのGuavaのweakKeys実装の内部 ses このアプローチ。

33
Louis Wasserman

よくあることの1つは、ソフト参照のマップを作成することです。

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;
}

私はここに私の古い学校を示しています-新しいJava=パッケージはおそらくこれを行うためのよりすっきりした方法を持っています。

5
PaulMurrayCbr

オブジェクトにWeakReferencesのみが含まれている場合(または参照がまったくない場合)、Javaがメモリ内により多くのスペースを確保する必要がある場合は常にガベージコレクションが行われます。したがって、WeakReferencesオブジェクトをメモリに残したいが、その状態を維持する必要がない場合(たとえば、Javaがオブジェクトをガベージコレクションする必要がある場合、問題ありません。どういうわけかそれを取り戻し、その間にJavaの方がパフォーマンスが優れています)

WeakReferenceをエンキューすると、ReferenceQueueを反復処理して、ガベージコレクションされたリファレンスとされていないリファレンスを判別できます。それだけです-これを知る必要がある場合にのみ行ってください。

続きを読む: http://weblogs.Java.net/blog/2006/05/04/understanding-weak-references

5
Patashu

ここでの質問が何であるかわからないが:

1)soft refは、jvmが本当にメモリを必要とするまで参照を保持しようとします。キャッシュ、特にLRUに最適です。グアバの多くの例を見てください。

2)弱い参照は、gcがオブジェクトを解放するのをまったく妨げようとしません。そのオブジェクトがまだどこかで使用されているかどうかを知りたい場合に使用されます。たとえば、スレッドとクラスに関する情報を格納するために使用されるため、スレッドまたはクラスが使用されなくなったときに、それに関連するメタ情報を破棄できます。

3)ファントム参照は弱いもののようですが、実際のオブジェクトを参照させることはできません。このようにして、ファントムを渡して実際のオブジェクトを再開できないようにすることができます(これは弱い参照のリスクです)。また、ファントム参照は、参照をクリアするまで、収集されるオブジェクトをブロックしています。

ReferenceQueue:そこには何も入れません。 gcが代わりにやってくれます。これらを使用すると、参照を1つずつ確認することなく、一部の参照が解放されるタイミングを知ることができます。

1
Uberto