ソフトリファレンス、弱リファレンス、虚リファレンス-彼らの特徴と応用シーン
8639 ワード
Java
の参照の定義は伝統的です.reference
のタイプのデータに格納されている数値が別のメモリの開始アドレスを表す場合、このメモリは参照を表すと呼ばれます.この定義は純粋ですが、狭すぎて、1つのオブジェクトがこの定義の下で引用されているか、引用されていないかの2つの状態しかなく、「食べ物の味がなく、捨てるのが惜しい」オブジェクトをどのように記述するかには力がありません.メモリ領域が十分である場合、メモリに保持できるオブジェクトについて説明したい.メモリ領域がゴミ収集後も非常に緊張している場合は、これらのオブジェクトを捨てることができます.多くのシステムのキャッシュ機能は、このようなアプリケーションシーンに合致しています.従来の2つのアプリケーションでは、オブジェクトのライフサイクルにおける複数の状態、オブジェクトがどのような状態を持っているかを記述することはできません.
Java
において、オブジェクトのライフサイクルは、以下の段階を含む.Created
)In Use
)Invisible
)Unreachable
)Collected
)Finalized
)De-allocated
)
static
,
,
, ,
アプリケーションフェーズ(
In Use
)オブジェクトは、少なくとも1つの強い参照によって保持される.非可視フェーズ(
Invisible
)オブジェクトが非可視フェーズにある場合、プログラム自体はオブジェクトの強い参照を持たないことを示します.これらの参照は依然として存在しますが.簡単に言えば、プログラムの実行はオブジェクトの役割ドメインを超えています.到達不可能フェーズ(
Unreachable
)オブジェクトが到達不可能フェーズにあるとは、オブジェクトが強い参照によって保持されなくなることを意味する.「非可視フェーズ」と比較して、「非可視フェーズ」とは、プログラムがオブジェクトの強い参照を持たないことを意味し、この場合、オブジェクトはJVM
などのシステムのいくつかのマウントされた静的変数またはスレッド、またはJNI
などの強い参照によって保持される可能性があり、これらの特別な強い参照は「GC root
」と呼ばれる.これらのGC root
が存在すると、オブジェクトのメモリが漏洩し、回収できません.収集フェーズ(
Collected
)ゴミ回収器が、オブジェクトが「到達不可能フェーズ」にあることを発見し、ゴミ回収器がオブジェクトのメモリ領域の再割り当ての準備ができていることを発見すると、オブジェクトは「収集フェーズ」に入る.オブジェクトがfinalize()
メソッドを書き換えた場合、そのメソッドの端末操作が実行される.ここでは特にfinazlie()をリロードしない方法を説明します!理由は2つあります.JVMのオブジェクトの割り当てと回収速度に影響します.このオブジェクトを割り当てる場合、JVMはゴミ回収器にそのオブジェクトを登録し、回収時にこのリロード方法を実行できるようにする必要があります.この方法の実行にはCPU時間がかかり、この方法を実行した後に回収操作が再実行される.すなわち、少なくともゴミ回収器がオブジェクトに対してGCを2回実行する必要がある.
オブジェクトの再「復活」をもたらす可能性がありますfinalize()メソッドでは、他の強い参照が再びオブジェクトを保持している場合、オブジェクトのステータスが「収集フェーズ」から「適用フェーズ」に変更されます.これはJavaオブジェクトのライフサイクルプロセスを破壊し、「復活」したオブジェクトは後続のコード管理を利用しません.
終了フェーズオブジェクトがfinalize()メソッドを実行した後も到達できない状態の場合、オブジェクトは終了フェーズに入ります.この段階では、ゴミ回収器がオブジェクト空間を回収するのを待つ.
オブジェクト空間再分配フェーズゴミ回収器は、そのオブジェクトが占有するメモリ空間を回収または再分配すると、そのオブジェクトが完全に消失し、「オブジェクト空間再分配フェーズ」と呼ばれる.
OutOfM moryError
のエラーを投げ出してプログラムを異常に終了させ、強い参照オブジェクトを勝手に回収してメモリ不足の問題を解決することはありません./**
*
* -Xmx200m -XX:+PrintGC
* Created by ccr at 2018/7/14.
*/
public class SoftReferenceDemo {
public static void main(String[] args) throws InterruptedException {
//100M
byte[] cacheData = new byte[100 * 1024 * 1024];
//
SoftReference cacheRef = new SoftReference<>(cacheData);
//
cacheData = null;
System.out.println(" GC " + cacheData);
System.out.println(" GC " + cacheRef.get());
// GC
System.gc();
// GC
Thread.sleep(500);
System.out.println(" GC " + cacheData);
System.out.println(" GC " + cacheRef.get());
// 120M ,
byte[] newData = new byte[120 * 1024 * 1024];
System.out.println(" " + cacheData);
System.out.println(" " + cacheRef.get());
}
}
GC null
GC [B@7d4991ad
[GC (System.gc()) 105728K->103248K(175104K), 0.0009623 secs]
[Full GC (System.gc()) 103248K->103139K(175104K), 0.0049909 secs]
GC null
GC [B@7d4991ad
[GC (Allocation Failure) 103805K->103171K(175104K), 0.0027889 secs]
[GC (Allocation Failure) 103171K->103171K(175104K), 0.0016018 secs]
[Full GC (Allocation Failure) 103171K->103136K(175104K), 0.0089988 secs]
[GC (Allocation Failure) 103136K->103136K(199680K), 0.0009408 secs]
[Full GC (Allocation Failure) 103136K->719K(128512K), 0.0082685 secs]
null
null
上記の例から分かるように、ソフトリファレンス関連オブジェクトは
GC
によって回収されない.JVM
は空間を割り当てる際にHeap
が不足すると対応するGC
が行われるが、今回のGC
ではソフトリファレンス関連のオブジェクトは収集されないが、JVMでは1回の回収を行っても不足(Allocation Failure
)であることが判明し、JVM
では2回目のGC
を試みソフトリファレンス関連のオブジェクトを回収する.このようなメモリが十分であれば、
GC
は保持され、メモリが不足し、GC
が収集される機能は、キャッシュの参照シーンに適しています.キャッシュを使用する場合、キャッシュにある場合はキャッシュから取得し、ない場合はデータベースから取得するという原則があります.キャッシュの存在は計算速度を速めるためです.キャッシュによってメモリ不足になり、プログラム全体がクラッシュすると、損をしません./**
*
* Created by ccr at 2018/7/14.
*/
public class WeakReferenceDemo {
public static void main(String[] args) throws InterruptedException {
//100M
byte[] cacheData = new byte[100 * 1024 * 1024];
//
WeakReference cacheRef = new WeakReference<>(cacheData);
System.out.println(" GC " + cacheData);
System.out.println(" GC " + cacheRef.get());
// GC
System.gc();
// GC
Thread.sleep(500);
System.out.println(" GC " + cacheData);
System.out.println(" GC " + cacheRef.get());
//
cacheData = null;
System.gc();
// GC
Thread.sleep(500);
System.out.println(" GC " + cacheData);
System.out.println(" GC " + cacheRef.get());
}
}
GC [B@7d4991ad
GC [B@7d4991ad
GC [B@7d4991ad
GC [B@7d4991ad
GC null
GC null
上記のコードから、弱い参照に関連付けられたオブジェクトが回収されるかどうかは、そのオブジェクトが他の強い参照を指しているかどうかにかかっていることがわかります.これは確かに理解しにくいが,弱い参照関連オブジェクトの生存周期と強い参照の差が少ない以上,直接強い参照を使ってよいのに,どうして弱い参照を作るのか.実は弱い引用は必然的に彼の応用シーンがある.
static Map
次のセクションは、Javaコア・テクノロジー・ボリューム1から抜粋します.
WeakHashMap
クラスを設計したのは、興味深い問題を解決するためです.値が1つあれば、対応するキーが使用されなくなり、どのような状況になりますか?あるキーに対する最後の参照が消滅し、この値を参照するオブジェクトがなくなったと仮定します.ただし、プログラム内の任意の部分にこのキーが表示されないため、このキー/値ペアはマッピングから削除できません.なぜゴミ回収機は削除できないのですか?不要なオブジェクトを削除するのはゴミ回収機の仕事ではないのでしょうか.残念なことに、事はこんなに簡単ではありません.ゴミ回収機はアクティブなオブジェクトを追跡します.マッピングオブジェクトがアクティブである限り、すべてのバケツもアクティブであり、回収できません.したがって,プログラムが長期にわたって生存しているマッピングテーブルから不要な値を削除する必要がある.あるいは
WeakHashMap
を使ってこのことを完成します.このデータ構造は、キーの一意の参照がハッシュ・エントリから来た場合、ゴミ回収器と連携してキー/値ペアを削除します.以下に、このメカニズムの内部動作を示します.
WeakHashMap
弱参照(weak references
)を使用してキーを保存します.WeakReference
オブジェクトは、参照を別のオブジェクトに保存します.ここでは、ハッシュキーです.このタイプのオブジェクトについては,ごみ回収器は特有の方法で処理される.通常、ゴミ回収器は、特定のオブジェクトが他の人に参照されていないことを発見した場合、それを回収します.ただし、オブジェクトがWeakReference
でしか参照できない場合、ゴミ回収器はそれを回収しますが、このオブジェクトを参照する弱い参照をキューに入れます.WeakHashMap
は、新しく追加された弱い参照を見つけるためにキューを周期的にチェックする.弱いリファレンスがキューに入ると、このキーは他の人に使用されず、収集されていることを意味します.すると、WeakHashMap
は、対応するエントリを削除する.WeakHashMap
が弱引用を用いたほか,ThreadLocal
クラスでも弱引用を用いた.get
メソッドであり、虚参照のget
メソッドは常にnull
を返し、弱い参照はReferenceQueue
を使用することができ、虚参照はReferenceQueue
と組み合わせて使用しなければならない.jdk
の直接メモリの回収は虚参照に用いられる.jvm
の自動メモリ管理の範囲はスタックメモリであるため、直接メモリはスタックメモリの外にあります(実はメモリマッピングファイルで、自分で仮想メモリ空間の関連概念を理解する)ため、直接メモリの割り当てと回収はUnsafe
種類が操作され、java
は直接メモリを申請した後、スタックメモリに1つのオブジェクトを割り当ててこのスタックの外に保存された参照を保存し、このオブジェクトはゴミ収集器に管理され、このオブジェクトが回収されると、対応するのユーザースレッドに通知が表示され、直接メモリがクリーンアップされます.