ディレクトリ
1、参照型
java.lang.ref
全体のパッケージ構造
タイプ | 対応するクラス | 機能 |
---|---|---|
強い参照 | 強い参照オブジェクトのGCを回復できません。 | |
ソフト参照 | SoftReference | 物理メモリは物理メモリが十分その後、リサイクルGCでない場合は、GCを回復するのに十分ではない場合。 |
弱参照 | 弱い参照 | スキャンは、その後、GCをリサイクルしたら |
偽の引用 | PhantomReference | いつでも、誰にも等しいです、オブジェクトの寿命には影響しませんGCを回収できる可能性があります |
最終的なリファレンス | 仕上げ機構(ファイナライズ)するため |
2、最終的なリファレンス
FinalReference
パッケージのアクセス、及び唯一のサブクラスFinalizer
、つつ、Finalizer
最終的な修飾クラスので、膨張は継承することができません。
そしてFinalizer
オブジェクトが関連付けられているfinalize()
現在のクラスがオーバーライドがある場合クラスのローディング時、方法、finalize()
方法、それはオブジェクトクラスファイナライザとしてマークされ、このタイプのオブジェクトは、その最初の呼び出しの前に回収することができますfinalize()
。
現在のオブジェクトがファイナライザタイプであり、(添付の非GC根を参照して)それ自体をしない場合、特定の実装機構、到達可能性分析のGC時間は、に追加されるReferenceQueue
キューの種類(F-キュー)です。システム初期化プロセスが、開始されFinalizerThread
た例デーモンスレッド(スレッド名のファイナライザ)、スレッド内のオブジェクトF-キューを消費していき、その実行finalize()
、(runFinalizer)の方法およびrunFinalizer方法はThrowableのレベルの例外を捕捉しますそのfinalize()
方法は、異常が生じないFinalizerThread
操作アボート。実装内のオブジェクトfinalize()
の方法は、あなただけ破るFinalizer
関連付けを、それはそれはすぐに回収される、または下のGCを待つという意味ではありません、そして各オブジェクトのfinalize()
メソッドは、一度だけ、繰り返さない実行されます。
finalize()
オブジェクトのメソッドは、死の運命を脱出する最後のチャンスである方法自体のオブジェクトのクラスのメンバ変数または変数オブジェクト(このキーワード)に割り当てられている場合、それは第二のマークで削除されます「しますリサイクルコレクション。」- 「Java仮想マシンの深い理解」
注:不適切なファイナライズ()のような、メモリリークやメモリオーバーフローを引き起こすことができSocksSocketImpl
ますサービスのクラスfinalize()
に参加close()
リソースを解放する操作を、しかし場合はFinalizerThread
可能なので、メモリリークされていない実装されていない、彼らはリソースの解放につながります。存在する場合のオブジェクトfinalize()
メソッドの実行時間が長すぎる、またはもたらす無限ループにあるF-Queue
メモリのオーバーフロー(OOM)を引き起こし、蓄積されています。
2.1、ファイナライザ
- FinalizerThread
//消费ReferenceQueue并执行对应元素对象的finalize()方法
private static class FinalizerThread extends Thread {
......
public void run() {
......
final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
running = true;
for (;;) {
try {
Finalizer f = (Finalizer)queue.remove();
f.runFinalizer(jla);
} catch (InterruptedException x) {
}
}
}
}
//初始化的时候启动FinalizerThread(守护线程)
static {
ThreadGroup tg = Thread.currentThread().getThreadGroup();
for (ThreadGroup tgn = tg;
tgn != null;
tg = tgn, tgn = tg.getParent());
Thread finalizer = new FinalizerThread(tg);
finalizer.setPriority(Thread.MAX_PRIORITY - 2);
finalizer.setDaemon(true);
finalizer.start();
}
- 追加
これは、JVMが参照キューを消費し始めると、デーモンスレッドを起動キュー、オブジェクトのファイナライズ()メソッドへの参照を呼び出します。
登録時のJVMは、ファイナライズ()メソッドを作成オーバーライド目標であるFinalizer
オブジェクト、およびオブジェクトが二重連結リストに追加されます。
static void register(Object finalizee) {
new Finalizer(finalizee);
}
private Finalizer(Object finalizee) {
super(finalizee, queue);
add();
}
private void add() {
synchronized (lock) { //头插法构建Finalizer对象的链表
if (unfinalized != null) {
this.next = unfinalized;
unfinalized.prev = this;
}
unfinalized = this;
}
}
:消費ファイナライザリストとキュー用の2つの追加のスレッドもあります
Runtime.runFinalization()
呼び出しrunFinalization()
消費ファイナライザキューのため、およびjava.lang.Shutdown
時間のJVM出口(JVMシャットダウンフック)にコールしますrunAllFinalizers()
消費ファイナリストのためには。
3、SoftReference
システムは、メモリ(OOM)の外に起こるために起こっている前に、ソフト参照を回復することになるが、また、十分なメモリの回復がない場合、メモリオーバーフロー例外がスローされます。
、あなたが最も軟らかい基準オブジェクトのパラメータの受け渡しになりますSoftReferenceクラスを使用します。
コンストラクタは、着信キュー時間をReferenceQueueオブジェクト参照が回収される場合、それはキューに追加されます。
public SoftReference(T referent) 根据传入的引用创建软引用
public SoftReference(T referent, ReferenceQueue<? super T> q)根据传入的引用和注册队列创建软引用
使用例:
ReferenceQueue<String> referenceQueue = new ReferenceQueue<>();
SoftReference<String> softReference = new SoftReference<>("abc", referenceQueue);
System.gc();
System.out.println(softReference.get());
Reference<? extends String> reference = referenceQueue.poll();
System.out.println(reference);
結果は以下の通りであります:
abc
null
ソフト参照キャッシュは、メモリに敏感な実装するために使用することができます
4、弱い参照
WeakReference
そしてSoftReference
ことを除いて、同様のWeakReference
GCが回収されたら、ライフサイクルが短くなり、発生しますが、GCスレッドの優先度が比較的低いので、それはWeakReference
すぐに発見され、GCを回復することはありません。
使用WeakReference
クラスは、渡された最も弱い参照の引数の対象となります。
コンストラクタは、着信キュー時間をReferenceQueueオブジェクト参照が回収される場合、それはキューに追加されます。
WeakReference(T referent) 根据传入的引用创建弱引用
WeakReference(T referent, ReferenceQueue<? super T> q) 根据传入的引用和注册队列创建弱引用
使用例:
public class WeakReferenceTest {
public static void main(String[] args) {
ReferenceQueue<String> rq = new ReferenceQueue<>();
//这里必须用new String构建字符串,而不能直接传入字面常量字符串
Reference<String> r = new WeakReference<>(new String("java"), rq);
Reference rf;
//一次System.gc()并不一定会回收A,所以要多试几次
while((rf=rq.poll()) == null) {
System.gc();
}
System.out.println(rf);
if (rf != null) {
//引用指向的对象已经被回收,存入引入队列的是弱引用本身,所以这里最终返回null
System.out.println(rf.get());
}
}
}
結果:
java.lang.ref.WeakReference@5a07e868
null
5、PhantomReference
仮想基準は、最も弱い型への参照である名前に平均参照の一部だけが存在します。ソフトおよび弱参照は異なる、ファントム参照がオブジェクトの寿命に影響を与えないであろうファントム参照オブジェクトのみを保持している場合、それはしないまで、基準点と等価ではないが、走査されるGCが回収され、ファントム参照ターゲット・オブジェクトの使用get()メソッド強いので、参照してターゲットオブジェクトを取得することができない、偽の参照は常に()メソッドはnullを返し得ます。
GCは、仮想物体の基準点を回収する際に基準を組み合わせて仮想キュー(ReferenceQueue)を参照する必要があり、仮想基準は、関連するキューに追加される指します。これは、GCの回復のために主に追跡アクティブ仮想ターゲットを指すキューは、リサイクルされようとしているかどうかを決定するための基準に対応する仮想オブジェクトを含むかどうかを参照することにより、。
仮想リファレンスシナリオをGC対応するオブジェクトを回収活動を追跡するために使用されます。
public PhantomReference(T referent, ReferenceQueue<? super T> q) 创建弱引用
例:
public class PhantomReferenceTest {
public static void main(String[] args) {
ReferenceQueue<String> rq = new ReferenceQueue<>();
PhantomReference<String> reference = new PhantomReference<>(new String("cord"), rq);
System.out.println(reference.get());
System.gc();
System.runFinalization();
System.out.println(rq.poll() == reference);
}
}
結果:
null
true
6、ReferenceQueue
ReferenceQueue内部データ構造は、リンクされたリストであり、要素は、参考例に加え、次いでスルーさwait
とnotifyAll
オブジェクトロック生産者と消費者を達成し、このようにキューをシミュレートします。
ReferenceQueue生産者と消費者の両方を達成するためにwati()とのnotifyAll()特定のシーンモードを使用します。
ReferenceQueueキーのソース分析:
- NULLとエンキュー
static ReferenceQueue<Object> NULL = new Null<>();
static ReferenceQueue<Object> ENQUEUED = new Null<>();
主に状態フラグを引用した参考文献の静的特性の両方が、キューに追加されNULL
、その基準は、現在のキューを介して除去されている識別、ENQUEUED
現在の基準の識別子がキューに追加されます。
- エンキュー(リファレンス<?延びT> R)
boolean enqueue(Reference<? extends T> r) { /* Called only by Reference class */
synchronized (lock) {
//检查该引用是否曾从当前队列移除过或者已经加入当前队列了,如果有则直接返回
ReferenceQueue<?> queue = r.queue;
if ((queue == NULL) || (queue == ENQUEUED)) {
return false;
}
assert queue == this;
r.queue = ENQUEUED;//将引用关联的队列统一标识为ENQUEUED
r.next = (head == null) ? r : head;//当前引用指向head
head = r; //将head指向当前引用(链表新增节点采用头插法)
queueLength++; //更新链表长度
if (r instanceof FinalReference) {
sun.misc.VM.addFinalRefCount(1); //
}
lock.notifyAll(); //通知消费端
return true;
}
}
- 削除(長いタイムアウト)
キューが指定されたタイムアウト時間まで待機空である場合、キューの先頭を除去しようとする要素を削除します。
public Reference<? extends T> remove(long timeout)
throws IllegalArgumentException, InterruptedException
{
if (timeout < 0) {
throw new IllegalArgumentException("Negative timeout value");
}
synchronized (lock) {
Reference<? extends T> r = reallyPoll();
if (r != null) return r; //如果成功移除则直接返回
long start = (timeout == 0) ? 0 : System.nanoTime();
for (;;) {
lock.wait(timeout); //释放当前线程锁,等待notify通知唤醒
r = reallyPoll();
if (r != null) return r;
if (timeout != 0) { //如果超时时间不为0则校验超时
long end = System.nanoTime();
timeout -= (end - start) / 1000_000;
if (timeout <= 0) return null; //如果剩余时间小于0则返回
start = end;
}
}
}
}
7、クリーナー
クリーナーはPhantomReference
、サブクラス実装よりも多く提供してfinalization(收尾机制)
クリーンアップロジッククリーナーがあるので、より軽量かつ堅牢な実装をReference.ReferenceHandler
直接コールするだけでなく、それは仮想基準のサブクラスであるので、それは、オブジェクトが指摘影響はありませんライフサイクル。
参照オブジェクトのレコードを例クリーナー、クリーンロジックのRunnableの例を含んでいます。参照のクリーナーポイントがGCをリサイクルされた後、Reference.ReferenceHandler
我々は、要素のキューの参照を消費し続けるとき、それはそのクリーン()メソッドを呼び出しますときの要素クリーナータイプ。
それは直接クリーナー、面倒で時間がかかる可能性が高いその他のクリーンアップタスクを遅らせReferenceHandlerスレッドブロックにつながるクリーンアップ・ロジックをあるときクリーナーは、代替ファイナライズ、軽量かつ使用に適したクリーンアップに十分なだけの論理的として使用されていません。
キーソース分析:
public class Cleaner extends PhantomReference<Object>
{
//一个统一的空队列,用于虚引用构造方法,Cleaner的trunk会被直接调用不需要通过队列
private static final ReferenceQueue<Object> dummyQueue = new ReferenceQueue<>();
//Cleaner内部为双向链表,防止虚引用本身比它们引用的对象先被gc回收,此为头节点
static private Cleaner first = null;
//添加节点
private static synchronized Cleaner add(Cleaner cl) {
if (first != null) { //头插法加入节点
cl.next = first;
first.prev = cl;
}
first = cl;
return cl;
}
//移除节点
private static synchronized boolean remove(Cleaner cl) {
//指向自己说明已经被移除
if (cl.next == cl)
return false;
//移除头部节点
if (first == cl) {
if (cl.next != null)
first = cl.next;
else
first = cl.prev;
}
if (cl.next != null)//下一个节点指向前一个节点
cl.next.prev = cl.prev;
if (cl.prev != null)//前一个节点指向下一个节点
cl.prev.next = cl.next;
//自己指向自己标识已被移除
cl.next = cl;
cl.prev = cl;
return true;
}
//清理逻辑runnable实现
private final Runnable thunk;
...
//调用清理逻辑
public void clean() {
if (!remove(this))
return;
try {
thunk.run();
} catch (final Throwable x) {
...
}
}
}
クリーナーは、外側のヒープメモリの管理を実現するために使用することができ、DirectByteBuffer
達成外部メモリヒープクリーナーによって回収されます。
DirectByteBuffer(int cap) { //构造方法中创建引用对象相关联的Cleaner对象
...
cleaner = Cleaner.create(this, new Deallocator(base, size, cap));
att = null;
}
private static class Deallocator implements Runnable {
...
public void run() { //内存回收的逻辑(具体实现参看源码此处不展开)
...
}
}
8、リファレンス
参照が挙げ汎用処理ロジックの数が内部で達成され、クリーナー共通の親クラスを含むいくつかの参考文献の上に例示されています。
基準状態のいくつかの例
アクティブ
アクティブ状態では、特別な処置はGC例を参照するときに変更GC到達可能性の検出が発生する際に、GCがその状態を変更します。参照インスタンスが作成されている場合は、この時点では2例、登録キューへの参照がある、それはそれ以外の場合は、非アクティブ状態になります、保留状態になります。アクティブに新しく作成されたインスタンスを参照します。
保留中
現在ReferenceHandlerスレッドの消費量であることを待っていると、その登録キューへの参照を追加し、リスト内の要素へのリファレンス保留。参照は、参照キューインスタンスが登録されていない場合は、状態に対処することはありません。
エンキュー
参照キューに登録し、この参照によって参照される作成されたインスタンスのキュー内の要素に属するキューの現在の状態。キュー・レジスタからの除去が非アクティブにその状態を変更した後ときの基準は、参考例です。参照は、参照キューインスタンスが登録されていない場合は、状態に対処することはありません。
不活発
非アクティブ状態は、任意の処理をせずに、一度それが状態になると非アクティブ状態が変更されることはありません。
次のようにマイグレーション全体的なフローチャートです。
キーソース決意
参考の1、いくつかの重要な属性
//关联的对象的引用,根据引用类型不同gc针对性处理
private T referent;
//引用注册的队列,如果有注册队列则回收引用会加入该队列
volatile ReferenceQueue<? super T> queue;
//上面引用队列referenceQueue中保存引用的链表
/* active: NULL //未加入队列前next指向null
* pending: this
* Enqueued: next reference in queue (or this if last)
* Inactive: this
*/
Reference next;
/* When active: 由gc管理的引用发现链表的下一个引用
* pending: pending链表中的下一个元素
* otherwise: NULL
*/
transient private Reference<T> discovered; /* used by VM */
/*
*等待入队列的引用链表,gc往该链表加引用对象,Reference-handler线程消费该链表。
* 它通过discovered连接它的元素
*/
private static Reference<Object> pending = null;
2、ReferenceHandler
private static class ReferenceHandler extends Thread {
...
public void run() {
while (true) {
tryHandlePending(true); //无限循环调用tryHandlePending
}
}
}
static {
... jvm启动时以守护线程运行ReferenceHandler
Thread handler = new ReferenceHandler(tg, "Reference Handler");
handler.setPriority(Thread.MAX_PRIORITY);
handler.setDaemon(true);
handler.start();
//注册JavaLangRefAccess匿名实现,堆外内存管理会用到(Bits.reserveMemory)
SharedSecrets.setJavaLangRefAccess(new JavaLangRefAccess() {
@Override
public boolean tryHandlePendingReference() {
return tryHandlePending(false);
}
});
}
//消费pending队列
static boolean tryHandlePending(boolean waitForNotify) {
Reference<Object> r;
Cleaner c;
try {
synchronized (lock) {
if (pending != null) {
r = pending;
// 'instanceof' might throw OutOfMemoryError sometimes
// so do this before un-linking 'r' from the 'pending' chain...
//判断是否为Cleaner实例
c = r instanceof Cleaner ? (Cleaner) r : null;
//将r从pending链表移除
pending = r.discovered;
r.discovered = null;
} else {
// The waiting on the lock may cause an OutOfMemoryError
// because it may try to allocate exception objects.
//如果pending没有元素可消费则等待通知
if (waitForNotify) {
lock.wait();
}
// retry if waited
return waitForNotify;
}
}
} catch (OutOfMemoryError x) {
//释放cpu资源
Thread.yield();
// retry
return true;
} catch (InterruptedException x) {
// retry
return true;
}
//调用Cleaner清理逻辑(可参考前面的7,Cleaner段落)
if (c != null) {
c.clean();
return true;
}
//如果当前引用实例有注册引用队列则将其加入引用队列
ReferenceQueue<? super Object> q = r.queue;
if (q != ReferenceQueue.NULL) q.enqueue(r);
return true;
}
概要
JVMが実現にはいくつかの種類があり、異なる種類のこれらのタイプのためのGCの参照が異なる回復メカニズムを持って、彼らはまた、SoftReferenceなど、独自のアプリケーションシナリオは、キャッシュに使用することができます持って、参照、弱い参照を使用することも可能PhantomReferenceは、このようなクリーナーなど、いくつかの特別な場面で使用されている間、いくつかの通常のキャッシュ(のWeakHashMapを)やることはメモリの外にヒープを再利用するために使用することができ、良いシナリオです。同時に、いくつかの弱いタイプの参照も回復関連する基準後にいくつかの追加の処理を実行することが可能となる、参照コホートの使用と組み合わせることができることSoftReference、弱い参照、PhantomReferenceは、偶数ファイナライザ(仕上げ機構)は、オブジェクト中に回収することができますオブジェクトのライフサイクルを変更します。
参考リンク:
https://www.ibm.com/developerworks/cn/java/j-fv/index.html
https://www.infoq.cn/article/jvm-source-code-analysis-finalreference
https://www.ibm.com/developerworks/cn/java/j-lo-langref/index.html
https://www.cnblogs.com/duanxz/p/10275778.html
「Java仮想マシンの深い理解」
https://blog.csdn.net/mazhimazh/article/details/19752475
https://www.tuicool.com/articles/AZ7Fvqb
https://blog.csdn.net/aitangyong/article/details/39455229
https://www.cnblogs.com/duanxz/p/6089485.html
https://www.throwable.club/2019/02/16/java-reference/#Reference状態の集合
http://imushan.com/2018/08/19/java/language/JDK%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB-Reference/