JavaのSoftReferenceとWeakReferenceの違いは何ですか?


811

9
SoftReferencesは、(実際にはそうではありませんが、説明のために)WeakReferencesのタイプです。これは通常、JVMがメモリ不足と判断したときに収集されます。
Ajeet Ganga

5
@ AjeetGanga、GCが実行されるたびに、緩い弱い参照が常に収集されます。stackoverflow.com/a/46291143/632951を
Pacerier '19

回答:


927

Ethan Nicholas著、弱い参照の理解から:

弱い参照

弱参照は、簡単に言えば、メモリに残ってオブジェクトを強制的に十分な強さではありません参照です。弱い参照を使用すると、ガベージコレクターの機能を利用して到達可能性を判断できるため、自分で行う必要はありません。次のような弱参照を作成します。

WeakReference weakWidget = new WeakReference(widget);

そしてweakWidget.get()、実際のWidgetオブジェクトを取得 するために使用できるコードの他の場所 。もちろん、弱い参照はガベージコレクションを防ぐのに十分強力ではないので、(ウィジェットへの強い参照がない場合) weakWidget.get()突然戻り始めnullます。

...

ソフトリファレンス

ソフト参照は、参照するオブジェクトを捨てることが少なく熱望していることを除いて、正確に弱い参照のようなものです。到達可能性が低いオブジェクト(オブジェクトへの参照が最も強いWeakReferences)は、次のガベージコレクションサイクルで破棄されますが、到達可能性が低いオブジェクトは、しばらくの間留まります。

SoftReferencesと動作が異なる必要はありませんWeakReferencesが、実際には、メモリが十分に 供給されている限り、ソフトに到達可能なオブジェクトは通常保持されます。これにより、上記のイメージキャッシュなどのキャッシュの優れた基盤になります。ガベージコレクターに、オブジェクトへの到達可能性(強力に到達可能なオブジェクトがキャッシュから削除されることはありません)とその悪さの両方を心配させることができるためです。彼らが消費しているメモリが必要です。

そして、ピーターケスラーはコメントに追加しました:

Sun JREはSoftReferencesをWeakReferencesとは異なる方法で処理します。利用可能なメモリに圧力がない場合、SoftReferenceによって参照されるオブジェクトを保持しようとします。1つの詳細:「-client」と「-server」のJREのポリシーは異なります。-clientJREはヒープを拡張するのではなくSoftReferencesをクリアすることを優先してフットプリントを小さくしようとしますが、-server JREはSoftReferencesをクリアするのではなく、(可能な場合は)ヒープを拡張することを優先することにより、パフォーマンスが向上します。1つのサイズですべてに対応できるわけではありません。


7
これ以上利用可能ポスト、あなたはウェイバックマシン上でそれを見つけることができます:web.archive.org/web/20061130103858/http://weblogs.java.net/blog/...
riccardo.tasso

今回は、アーカイブは利用できなくなりました
user1506104 '27年

209

弱い参照は熱心に収集されます。オブジェクトが弱い到達可能性(弱い参照を介してのみ到達可能)をGCが検出した場合、GCはそのオブジェクトへの弱い参照をすぐにクリアします。そのため、プログラムは、クラスに関するキャッシュされたリフレクション情報やオブジェクトのラッパーなど、「関連付けられた情報」をプログラムが(強く参照して)保持しているオブジェクトへの参照を保持するのに適しています。それが関連付けられているオブジェクトがGCされた後に保持する意味はありません。弱参照がクリアされると、コードがどこかでポーリングする参照キューに入れられ、関連するオブジェクトも破棄されます。つまり、オブジェクトに関する追加情報を保持しますが、そのオブジェクトが参照するオブジェクトがなくなると、その情報は不要になります。実は 特定の状況では、WeakReferenceをサブクラス化して、オブジェクトに関連する追加情報をWeakReferenceサブクラスのフィールドに保持することもできます。WeakReferenceのもう1つの一般的な用途は、正規のインスタンスを保持するためにマップと組み合わせて使用​​することです。

一方、SoftReferencesは外部の再作成可能なリソースをキャッシュするのに適しています。GCは通常、リソースのクリアを遅らせるからです。ただし、OutOfMemoryErrorがスローされる前にすべてのSoftReferenceがクリアされることが保証されているため、理論的にはOOME [*]が発生することはありません。

典型的なユースケースの例は、ファイルのコンテンツの解析された形式を保持することです。ファイルをロードして解析し、解析された表現のルートオブジェクトへのSoftReferenceを保持するシステムを実装します。次にファイルが必要になったときに、SoftReferenceを介してファイルを取得しようとします。それを取得できる場合は、別のロード/パースを行わず、GCがその間にそれをクリアした場合は、リロードします。そうすることで、パフォーマンスの最適化に空きメモリを利用できますが、OOMEのリスクはありません。

次に[*]です。SoftReferenceを保持しても、それ自体でOOMEを引き起こすことはできません。一方、WeakReferenceを使用するタスクで誤ってSoftReferenceを使用する場合(つまり、オブジェクトに関連付けられた情報を何らかの方法で強く参照し、参照オブジェクトがクリアされたときに破棄する)、次のようにOOMEを実行できます。 ReferenceQueueをポーリングして関連オブジェクトを破棄するコードは、タイムリーに実行されない場合があります。

したがって、決定は使用法に依存します-構築するのにコストがかかりますが、他のデータから再構築できる場合は、ソフト参照を使用します-一部のデータの正規インスタンスへの参照を保持している場合、または「所有」せずにオブジェクトへの参照を持っている(そのため、オブジェクトがGCされないようにする)には、弱い参照を使用します。


14
弱いオブジェクトがいつ使用されるかを説明するのに特に役立ちます。
Jack BeNimble 2012年

aの適切な使用に関する重要な点は、WeakReferenceそれを使用する必要がある場所では、参照が範囲外になった後しばらくの間有効である可能性があるという事実は許容できるかもしれませんが、望ましくないということです。
スーパーキャット2015

キー値オブジェクトへの弱い参照が常に生成される場合、WeakHashMapの使用方法を理解するのに苦労していますか?

@ supercat、GCの実行を監視するのが適切な使用法は1つだけWeakReferenceです。詳しくはこちらをご覧ください:stackoverflow.com/a/46291143/632951
Pacerier '19

1
@Pacerier:その投稿の著者は単に間違っています。彼は、イベントサブスクリプションのような他のいくつかの使用シナリオを無視し、2番目のポイントは無意味であり、3番目のポイントは、プログラマーが不可能なことを実行できると想定しています。彼の最初の点は合理的ですが、私が言ったことと直接関係があります。たとえば、コードが頻繁に大きな不変オブジェクトを構築および比較する必要がある場合、コードがすでに存在するかどうかに関係なくコードが新しいオブジェクトを作成する場合、構築部分はしばしば安価になりますが、オブジェクトとそれ自体(同一の参照)との比較は...
スーパーキャット'19

155

Javaでは ; 強いものから弱いものへの順序があります:強い、柔らかい、弱い、ファントム

強い参照は、 GCによってコレクションから参照されるオブジェクトを保護する通常の参照です。つまり、ガベージコレクションは行われません。

ソフト参照は、ガベージコレクタによって収集の対象であるが、そのメモリが必要になるまで、おそらく収集されることはありません。つまり、ガベージコレクションの前にOutOfMemoryError

弱参照は、 GCによってコレクションから参照されるオブジェクトを保護しない基準です。つまり、ストロングまたはソフトの参照がない場合、ガベージコレクションが行われます。

A ファントム参照は、オブジェクトへの参照は、想像線ことが確定された後の参照が、その割り当てられたメモリが再利用される前です。

ソース

類推: JVMが王国であり、オブジェクトが王国の王であり、GCがキング(オブジェクト)を殺そうとする王国の攻撃者であると仮定します。

  • キングが強いとき、GCは彼を殺すことができません。
  • キングがソフトであるとき、GCは彼を攻撃しますが、リソースが利用可能になるまで、キングは保護して王国を支配します。
  • キングがウィークであるとき、GCは彼を攻撃しますが、保護なしで王国を支配します。
  • キングがファントムのとき、GCはすでに彼を殺しましたが、キングは彼の魂を介して利用できます。

7
ソフトリファレンス... until memory is availableは意味がありません。もしかしてis eligible for collection by garbage collector, but probably won't be collected until its memory is needed for another use
ToolmakerSteve、2015年

1
はい、ガベージコレクターは、メモリが使用可能になるまで参照を収集しません。
Premraj

2
私は簡単な説明が好きで、私からあまり多くのbla bla bla +1を使わないでください!
アデリン

3
革新的な例を含む優れた要約
Ravindra


77

弱参照 http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/ref/WeakReference.html

原則: weak referenceガベージコレクションに関連しています。通常、1つ以上のオブジェクトreferenceはガベージコレクションの対象にはなりません。
上記の原則は、適用される場合には適用されませんweak reference。オブジェクトに他のオブジェクトとの弱い参照しかない場合、ガベージコレクションの準備ができています。

以下の例を見てみましょうMap。Keyがオブジェクトを参照するwith Objectsがあります。

import java.util.HashMap;   
public class Test {

    public static void main(String args[]) {
        HashMap<Employee, EmployeeVal> aMap = new 
                       HashMap<Employee, EmployeeVal>();

        Employee emp = new Employee("Vinoth");
        EmployeeVal val = new EmployeeVal("Programmer");

        aMap.put(emp, val);

        emp = null;

        System.gc();
        System.out.println("Size of Map" + aMap.size());

    }
}

さて、作成したプログラムの実行中にemp = nullMapそのままキーを押し続けると、ここでは意味がありませんnull。上記の状況では、オブジェクトはガベージコレクションされません。

WeakHashMap

WeakHashMapからエントリkey-to-value mappingsを取得することができなくなったときに、エントリ()が削除されますMap

上記の例をWeakHashMapと同じように示します

import java.util.WeakHashMap;

public class Test {

    public static void main(String args[]) {
        WeakHashMap<Employee, EmployeeVal> aMap = 
                    new WeakHashMap<Employee, EmployeeVal>();

        Employee emp = new Employee("Vinoth");
        EmployeeVal val = new EmployeeVal("Programmer");

        aMap.put(emp, val);

        emp = null;

        System.gc();
        int count = 0;
        while (0 != aMap.size()) {
            ++count;
            System.gc();
        }
        System.out.println("Took " + count
                + " calls to System.gc() to result in weakHashMap size of : "
                + aMap.size());
    }
}

出力:トック20 calls to System.gc()での結果にaMap sizeする:0。

WeakHashMapキーへの弱い参照のみがあり、他のMapクラスのような強い参照はありません。を使用したにもかかわらず、値またはキーが強く参照されている場合に注意する必要がある状況がありますWeakHashMap。これは、オブジェクトをWeakReferenceでラップすることで回避できます。

import java.lang.ref.WeakReference;
import java.util.HashMap;

public class Test {

    public static void main(String args[]) {
        HashMap<Employee, EmployeeVal> map = 
                      new HashMap<Employee, EmployeeVal>();
        WeakReference<HashMap<Employee, EmployeeVal>> aMap = 
                       new WeakReference<HashMap<Employee, EmployeeVal>>(
                map);

        map = null;

        while (null != aMap.get()) {
            aMap.get().put(new Employee("Vinoth"),
                    new EmployeeVal("Programmer"));
            System.out.println("Size of aMap " + aMap.get().size());
            System.gc();
        }
        System.out.println("Its garbage collected");
    }
}

ソフト参照。

Soft Referenceその弱参照よりわずかに強いです。ソフトリファレンスはガベージコレクションを可能にしますが、ガベージコレクターに他のオプションがない場合にのみそれをクリアするように要求します。

ガベージコレクターは、弱く到達可能なオブジェクトとは異なり、弱く到達可能なオブジェクトを積極的に収集しません。代わりに、メモリが本当に必要な場合にのみ、弱く到達可能なオブジェクトを収集します。ソフト参照は、ガベージコレクターに「メモリが不足していなければ、このオブジェクトを保持したいのですが、メモリが非常に不足している場合は、先に進んでそれを収集して対処します。それと。" ガベージコレクターは、スローする前にすべてのソフト参照をクリアする必要がありOutOfMemoryErrorます。


5
あなたは得ることができますNullPointerExceptionではaMap.get().put(...)
xehpuk 2015

最初のHashMapの例は間違っています。「aMap.put(emp、val);」を実行すると 「emp」と「val」はどちらも強力な参照です。内部的には、「emp」と「val」を保持するために新しい変数が作成されるため、「emp = null;」を実行すると あなたは単に「emp」変数を無効にしますが、ハッシュマップ(まだ元のEmployeeオブジェクトを保持している)に対して内部的に変数を無効にしていません。したがって、ハッシュマップは、外部で 'emp'変数をどのように処理するかに関係なく、依然として 'emp'への強い参照を保持します。
ティアゴ

@ティアゴ。いいえ。おそらく「最初の例」とは、そのWeakHashMap例を指しているものです(それが弱い動作を示している最初の例であるため)。「WeakHashMap」のドキュメントを見てください。WeakHashMap "An entry in a WeakHashMap will automatically be removed when its key is no longer in ordinary use. " を使用することの全体的なポイントは、WeakReferenceを宣言/渡す必要がないことです。WeakHashMapは内部的にそれを行います。docs.oracle.com/javase/7/docs/api/java/util/WeakHashMap.html
ToolmakerSteve

System.gc()の呼び出しを0にすると、weakHashMapのサイズは次のようになります。0は2番目のプログラムの出力ですか。
アデリン

1
WeakHashMap動作中の別の例として、ガベージコレクションの実行後にのみエントリがどのように削除されるかを示すサンプルアプリを使用して、質問への私の回答を参照しください
バジルブルク2018年

50

ソフトリファレンスとウィークリファレンスの本当の違いは、

ガベージコレクターはアルゴリズムを使用して、ソフトに到達可能なオブジェクトを再利用するかどうかを決定しますが、常に弱く到達可能なオブジェクトを再利用します。


@ ATorras、Samir。私はこの答えをここで拡張しました:stackoverflow.com/a/46291143/632951
Pacerier '19

25

SoftReferenceキャッシュ用に設計されています。がWeakReference他の方法では到達できないオブジェクトを参照していることが判明した場合、そのオブジェクトはすぐにクリアされます。SoftReferenceそのままにすることができます。通常、空きメモリの量と、クリアする必要があるかどうかを判断するために最後に使用された時間に関連するアルゴリズムがいくつかあります。現在のSunのアルゴリズムでは、Javaヒープにメガバイトの空きメモリがあるため、何秒も使用されなかった場合、参照をクリアします(構成可能なサーバーHotSpotは、で設定された最大可能ヒープに対してチェックします-Xmx)。SoftReferencesはOutOfMemoryError、他に到達可能でない限り、スローされる前にクリアされます。


9
しかし、Androidの中で、それはキャッシュのために推奨されませんdeveloper.android.com/reference/java/lang/ref/...
ヤロスラフMytkalyk

4
@DoctororDrive tbf質問はdalvikではなく、javaに関するものでした。:-P
fabspro

2
@YaroslavMytkalyk、率直に言って、Androidがクラスの動作を書き直したい場合は、独自の名前空間を使用する必要がありますjava.lang。このような同義語の乱用は、何の役にも立ちません。
パセリエ2017

9

この記事は、強い参照、弱い参照、弱い参照、および幻の参照を理解するのに非常に役立ちます。


要約すると、

オブジェクトへの弱い参照のみがある場合(強い参照がない場合)、オブジェクトは次のGCサイクルでGCによって再利用されます。

オブジェクトへのソフト参照のみ(強い参照なし)がある場合、オブジェクトは、JVMがメモリを使い果たしたときにのみ、GCによって再利用されます。


つまり、強い参照には究極の力があります(GCで収集することはできません)。

ソフト参照は弱い参照よりも強力です(JVMがメモリ不足になるまでGCサイクルを回避できるため)。

弱参照は、ソフト参照よりも強力ではありません(オブジェクトが他の強参照を持たない場合は、GCサイクルを超えることができず、再利用されるため)。


レストランのアナロジー

  • ウェイター-GC
  • あなた-ヒープ内のオブジェクト
  • レストランエリア/スペース-ヒープスペース
  • 新規顧客-レストランにテーブルが必要な新しいオブジェクト

これで、強い顧客(強い参照に類似)の場合、新しい顧客がレストランに来た場合や何が起こったとしても、テーブル(ヒープ上のメモリ領域)を離れることは決してありません。ウェイターはあなたにレストランを去るように言う(またはあなたに要求する)権利はありません。

あなたがソフト顧客(ソフト参照に類似)の場合、新しい顧客がレストランに来ても、ウェイターは新しい顧客を収容する他の空のテーブルがない限り、テーブルを離れるように求めません。(言い換えれば、ウェイターは、新しい顧客が参入し、この新しい顧客に他のテーブルが残っていない場合にのみ、テーブルを離れるように求めます)

あなたが弱い顧客(弱い参照に類似)である場合、ウェイターは彼の意志で(いつでも)レストランを出るように頼むことができます:P


7

唯一の本当の違い

ドキュメントごとに実行中のGCによって緩いWeakReferencesをクリアする必要あります。

ドキュメントごと、ルーズなSoftReferences OOMがスローされる前にクリアされる必要あります。

それが唯一の本当の違いです。他のすべては契約の一部ではありません。(私は最新のドキュメントが契約であると仮定します。)

SoftReferencesは便利です。メモリ依存のキャッシュは、WeakReferencesではなくSoftReferencesを使用します。


WeakReference の唯一の適切な使用法は、GCの実行を観察することです。これを行うには、オブジェクトがすぐにスコープから外れる新しいWeakReferenceを作成し、次にnullを取得しようとしますweak_ref.get()。になるnullと、この期間の間にGCが実行されたことがわかります。

用として正しくない弱い参照の使用、リストは無限大です。

  • あなたは1を記述する必要はありません、というように優先-2 softreference実装するためのお粗末なハックはまだ期待通りにキャッシュがでクリアされるので、それは仕事をしませんすべてのスペアメモリがある場合でも、GCの実行を。フェイルについては、https: //stackoverflow.com/a/3243242/632951を参照して ください。(それに加えて、2レベル以上のキャッシュ優先度が必要な場合はどうなりますか?それでも、実際のライブラリが必要になります。)

  • 既存のクラスのオブジェクトに関連付けるデータにお粗末なハック、まだあなたのGCは、あなたのweakreferencesが作成された後、休憩を取ることを決定したとき、それはメモリリーク(のOutOfMemoryError)を作成します。その上、それは醜いことを超えています:より良いアプローチはタプルを使うことです。

  • 既存のクラスのオブジェクトにデータを関連付けるための粗末なハック。クラスはそれ自体をサブクラス化不可能にする神経を持ち、呼び出す必要がある既存の関数コードで使用されます。そのような場合、適切な解決策は、クラスを編集してサブクラス化できるようにするか、関数を編集してクラスではなくインターフェイスを取るようにするか、代替関数を使用することです。


キーのタイプequals()が単なるオブジェクトID であるキャッシュについてはどうですか?ソフト参照は無駄に見えます。キーオブジェクトに到達できなくなると、そのマッピングを再度検索することはできないためです。
HighCommander4 2017年

同意しません。とにかくGCに影響を与えたくない場合は、WeakReferenceを使用します(オブジェクト参照を保存して、それがまだ存在するかどうかを、設定を行わずに後で確認したい場合があります)。GCに影響を与えてオブジェクトを保持しようとする場合(つまり、GCがオブジェクトを保持することを望む場合)は、SoftReferenceを使用します。
デビッドレファエリ

WeakReferenceを使用する良い例は、AndroidのAsyncTaskにあり、コンテキストのインスタンスを保持します。こうすることで、コンテキストが停止した場合(アクティビティ-画面の回転など)、AsyncTaskはコンテキストへの強い参照を持たなくなり、ガベージコレクションを実行できます。youtu.be/…を
David Refaeli

3

Javaの6種類のオブジェクト到達可能性状態:

  1. 強力な到達可能オブジェクト-GCは、この種のオブジェクトを収集(が占有するメモリを解放)しません。これらは、ルートノードまたは別の強力に到達可能なオブジェクト (つまり、ローカル変数、クラス変数、インスタンス変数など)を介して到達可能です。
  2. 柔らかく到達可能なオブジェクト- メモリの競合によっては、GC この種のオブジェクトを収集しようとする場合があります。これらは、ルートから1つ以上のソフト参照オブジェクトを介して到達可能です
  3. 到達範囲の弱いオブジェクト-GCはこの種のオブジェクトを収集する必要があります。これらは、1つ以上の弱参照オブジェクトを介してルートから到達可能です
  4. 復活可能なオブジェクト-GCはすでにこれらのオブジェクトを収集中です。しかし、彼らはいずれかの状態に戻る可能性があります-いくつかのファイナライザの実行により、強い/柔らかい/弱い
  5. ファントム到達可能オブジェクト-GC はすでにこれらのオブジェクトを収集中であり、ファイナライザによって復活できないと判断しました(finalize()メソッド自体を宣言すると、ファイナライザが実行されます)。これらは、1つ以上のファントム参照オブジェクトを介してルートから到達可能です
  6. 到達不能なオブジェクト-オブジェクトは強く、柔らかく、弱くもなく、ファントムにも到達できず、復活できません。これらのオブジェクトは再利用の準備ができています

詳細:https : //www.artima.com/insidejvm/ed2/gc16.html «折りたたむ


4
ファントム参照の良い説明ではありません。また、4つのタイプを固有の順序でリストしました。「ファントム」は最も弱いタイプであり、最も強いタイプではありません。これらをリストする従来の順序は、「強い、柔らかく、弱い、幻影」です。そして、ファントムオブジェクトがキャッシングメカニズムに使用されるという概念をどこで入手したかはわかりません。AFAIK、それらはGCによってのみ見られる一時的な状態であり、通常のプログラマーが作業するものではありません。
ToolmakerSteve

@ToolmakerSteveおよびすべて-いくつかのお詫び1.以前のバージョンの私の回答でのファントム参照の誤った説明、および2.エラーの修正の遅延。エラーを修正することで、答えが改善されました
V.Vidyasagar

1

弱参照オブジェクトは、弱参照のみがある場合にのみ収集されることに注意してください。強い参照が1つしかない場合は、弱い参照がいくつあっても収集されません。


これは常識です... softrefとphantomrefについても同様です。
パセリエ2017

1

動作中のメモリ使用状況を示すために、プログラムの最後までそれらを保持することにより、重いオブジェクトの重い負荷の下で、Strong、Soft、Weak&Phantomリファレンスを使用して実験を行いました。次に、ヒープの使用状況とGCの動作を監視しました。これらのメトリックはケースバイケースで異なる場合がありますが、確かに高いレベルの理解を提供します。以下は調査結果です。

高負荷時のヒープとGCの動作

  • 強参照/ハード参照 -プログラムの継続中、JVMは保持された強参照オブジェクトを収集できませんでした。最終的には「java.lang.OutOfMemoryError:Java heap space」になりました
  • ソフトリファレンス -プログラムが続くにつれて、ヒープ使用量は増加し続けましたが、OLD gen GCは最大ヒープに近づいたときに発生しました。プログラムを開始した後、GCは少し遅れて開始しました。
  • 弱い参照 -プログラムが始まると、オブジェクトはすぐにファイナライズおよび収集され始めました。ほとんどのオブジェクトは、若い世代のガベージコレクションで収集されました。
  • ファントム参照 -弱参照と同様に、ファントム参照オブジェクトもファイナライズされ、ガベージコレクションがすぐに開始されます。古い世代のGCはなく、すべてのオブジェクトは若い世代のガベージコレクション自体に収集されていました。

この実験の詳細なグラフ、統計、観測については、こちらをご覧ください


0

WeakReference:弱く参照されるだけのオブジェクトは、すべてのGCサイクル(マイナーまたはフル)で収集されます。

SoftReference:ソフト参照のみのオブジェクトが収集されるタイミングは、以下に依存します。

  1. -XX:SoftRefLRUPolicyMSPerMB = Nフラグ(デフォルト値は1000、別名1秒)

  2. ヒープ内の空きメモリの量。

    例:

    • ヒープには10MBの空き容量があります(フルGC後)。
    • -XX:SoftRefLRUPolicyMSPerMB = 1000

    次に、SoftReferenceによってのみ参照されるオブジェクトは、最後にアクセスされた時間が10秒より大きい場合に収集されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.