弱参照の使用は実装の見たことがないので、それらの使用例とは何か、そして実装がどのように機能するかを理解しようとしています。WeakHashMap
またはを使用する必要WeakReference
があったのはいつですか?
弱参照の使用は実装の見たことがないので、それらの使用例とは何か、そして実装がどのように機能するかを理解しようとしています。WeakHashMap
またはを使用する必要WeakReference
があったのはいつですか?
回答:
強い参照の1つの問題は、特に画像のような非常に大きな構造でのキャッシングです。私が取り組んでいるWebサイト設計ツールのように、ユーザーが提供した画像を処理する必要があるアプリケーションがあるとします。当然、これらのイメージをキャッシュする必要があります。ディスクからロードするのは非常にコストがかかり、メモリ内に(巨大になる可能性のある)イメージの2つのコピーが同時に存在する可能性を避けたいからです。
画像キャッシュは、私たちが絶対に必要としない場合に画像をリロードするのを防ぐことになっているので、キャッシュには常にメモリ内にある画像への参照が常に含まれるべきであることがすぐにわかります。ただし、通常の強力な参照では、その参照自体がイメージをメモリに残します。そのため、イメージがメモリで不要になったときを何らかの方法で判断し、キャッシュから削除して、ガベージコレクションの対象にすることができます。ガベージコレクターの動作を複製し、オブジェクトをメモリ内に置くかどうかを手動で決定する必要があります。
弱い参照の理解、イーサン・ニコラス
WeakHashMap
。
WeakReference
対 SoftReference
明確にすべき1つの違いは、a WeakReference
とaの違いSoftReference
です。
基本的に、a WeakReference
は、参照されるオブジェクトがハード参照を持たなくなると、JVMによって熱心にGC-dされます。一方、Dオブジェクトそれは本当にメモリを再利用するために必要になるまで、ガベージコレクタによって約残される傾向があります。SoftReference
値がWeakReference
s 内に保持されるキャッシュは、ほとんど役に立ちません(で、WeakHashMap
弱く参照されるのはキーです)。SoftReferences
使用可能なメモリで拡大および縮小できるキャッシュを実装する場合に値をラップするのに便利です。
特にWeakReference
とWeakHashMap
の一般的な用途の1つは、オブジェクトにプロパティを追加することです。場合によっては、機能またはデータをオブジェクトに追加する必要がありますが、サブクラス化や構成はオプションではありません。その場合、追加したいプロパティに拡張するオブジェクトをリンクするハッシュマップを作成するのが明らかです。 。その後、プロパティが必要なときはいつでも、マップで調べることができます。ただし、プロパティを追加しているオブジェクトが破壊されて大量に作成される傾向がある場合、マップ内の多くの古いオブジェクトが大量のメモリを消費することになります。
WeakHashMap
代わりにaを使用すると、オブジェクトはプログラムの残りの部分で使用されなくなるとすぐにマップを離れます。これは望ましい動作です。
私はするいくつかのデータを追加するには、この操作を行う必要がありましたjava.awt.Component
(1.4.2と1.5の間JREの変化を回避するために、私はすべてのコンポーネント私が興味を持ってint型だったサブクラス化することで、それを固定している可能性がJButton
、JFrame
、JPanel
....)が、これはあまりでしたはるかに少ないコードで簡単に。
WeakHashMap
およびのもう1つの便利なケースWeakReference
は、リスナーレジストリの実装です。
特定のイベントをリッスンしたいものを作成するとき、通常はリスナーを登録します、例えば
manager.registerListener(myListenerImpl);
がmanager
リスナーをに保存している場合、これは、WeakReference
たとえばを使用してレジスタを削除する必要がないことを意味します。manager.removeListener(myListenerImpl)
これは、リスナーまたはリスナーを保持しているコンポーネントが利用できなくなると、レジスタが自動的に削除されるためです。
もちろん、手動でリスナーを削除することもできますが、削除しない場合や忘れた場合でも、メモリリークは発生せず、リスナーのガベージコレクションが妨げられることもありません。
どこにWeakHashMap
絵が入っていますか?
登録されたリスナーをWeakReference
s として格納するリスナーレジストリには、これらの参照を格納するためのコレクションが必要です。WeakHashSet
標準のJavaライブラリには実装はありませんWeakHashMap
が、後者は簡単に最初のライブラリの機能を「実装」するために使用できます。
Set<ListenerType> listenerSet =
Collections.newSetFromMap(new WeakHashMap<ListenerType, Boolean>());
これとともに listenerSet
新しいリスナーを登録するには、それをセットに追加するだけでよく、明示的に削除されなくても、リスナーが参照されなくなった場合は、JVMによって自動的に削除されます。
WeakHashMap
必要なときはいつでも別の便利なケースと言えるでしょうHashMap
。そのため、objがスコープ外になるとアイテムが自動的に削除されるため、hashmap.remove を手動で実行する必要はありません。文字通り魔法!このような醜い魔法のハックは、完全な顔面攻撃です。
WeakReference
、コードベースが大幅に簡素化され、登録解除に失敗することに関連する不要なバグが回避されます。どのような欠点ですか?
このブログ投稿では、両方のクラスの使用方法を示します。Java:IDで同期する。使い方は次のようになります:
private static IdMutexProvider MUTEX_PROVIDER = new IdMutexProvider();
public void performTask(String resourceId) {
IdMutexProvider.Mutex mutext = MUTEX_PROVIDER.getMutex(resourceId);
synchronized (mutext) {
// look up the resource and do something with it
}
}
IdMutextProviderは、同期するためのIDベースのオブジェクトを提供します。要件は次のとおりです。
これは、次のタイプの内部ストレージマップを使用して実現されます。
WeakHashMap<Mutex, WeakReference<Mutex>>
オブジェクトはキーと値の両方です。マップの外部にオブジェクトへのハード参照がない場合は、ガベージコレクションすることができます。マップ内の値はハード参照で格納されるため、メモリリークを防ぐために、値をWeakReferenceでラップする必要があります。この最後の点は、javadocで説明されています。
たとえば、特定のクラスで作成されたすべてのオブジェクトを追跡したい場合。これらのオブジェクトのガベージコレクションを許可するには、オブジェクト自体ではなく、オブジェクトへの弱参照のリスト/マップを保持します。
誰かがファントム参照を私に説明できたら、私は幸せになります...
上記のように、弱い参照は強い参照が存在する限り保持されます。
使用例としては、リスナー内でWeakReferenceを使用し、ターゲットオブジェクトへのメイン参照がなくなるとリスナーがアクティブでなくなるようにします。これは、WeakReferenceがリスナーリストから削除されることを意味しないことに注意してください。クリーンアップは引き続き必要ですが、たとえば、スケジュールされた時間に実行できます。これは、リッスンされたオブジェクトが強い参照を保持することを防ぎ、最終的にはメモリの膨張の原因になるという影響もあります。例:ウィンドウよりもライフサイクルが長いモデルを参照するSwing GUIコンポーネント。
上記のようにリスナーと遊んでいると、オブジェクトがユーザーの視点から「即座に」収集されることにすぐに気付きました。
WeakReferencesで私が実際に使用した例の1つは、めったに使用されない単一の非常に大きなオブジェクトがある場合です。不要なときにメモリに保持したくない。しかし、別のスレッドが同じオブジェクトを必要とする場合、それらのうちの2つをメモリーに入れたくないでしょう。オブジェクトへの弱い参照と、それを使用するメソッドのハード参照を保持できます。メソッドが両方とも終了すると、オブジェクトが収集されます。
「new WeakHashMap()」をGoogleコードで検索しました。
GNUクラスパスプロジェクトからたくさんのマッチを取得し、
weakhashmapを使用して、拡張オブジェクトの作成のためにリソースフリーのキャッシュを実装できます。
しかし、変更可能なオブジェクトを持つことは望ましくないことに注意してください。クエリの結果(実行に約400ミリ秒かかる)を、ほとんど更新されないテキスト検索エンジンにキャッシュするために使用しました。