最近、「JVMの詳細な理解」という本を読んでいましたが、資料と本にはまだ違いがあり、本にはまだいくつかの点が残っています。急いで友達とシェアしてね〜
オブジェクトをリサイクルできるかどうかを確認する方法
そのガベージコレクションがそれであるので、まず間違いなく、リサイクルすることができるかを決定するために行くの、私たちはしばしばここにあることを言う
引用计数法
井戸が可达性分析法
。
参照カウント
参照カウント->オブジェクトが別の場所によって一度参照されると、カウンター値は+1になります。逆に、参照先が無効になると、カウンターの値が-1されます。カウンター値が0の場合、オブジェクトがそれを参照していないことを意味します。同時に、誰もがその欠点を知っていると思います。つまり、循環依存の問題を完全に解決することはできません。
デモ:
package com.montos.test.first;
public class TestReferenceCounting {
public Object instance = null;
private byte[] bigSize= new byte[2*1024*1024];
public static void main(String[] args) {
TestReferenceCounting objA = new TestReferenceCounting();
TestReferenceCounting objB = new TestReferenceCounting();
objA.instance = objB;
objB.instance = objA;
objA = null;
objB =null;
// objA 与 objB 是否会被回收️?
System.gc();
}
}
复制代码
プログラムの実行中に上記を見てみましょう。オブジェクトobjA
とオブジェクトobjB
はリサイクルされますか?gc.log
0.148: [GC (System.gc()) 0.149: [SoftReference, 0 refs, 0.0000372 secs]0.149: [WeakReference, 12 refs, 0.0000104 secs]0.149: [FinalReference, 74 refs, 0.0000356 secs]0.149: [PhantomReference, 0 refs, 0 refs, 0.0000104 secs]0.149: [JNI Weak Reference, 0.0000129 secs][PSYoungGen: 6717K->560K(76288K)] 6717K->568K(251392K), 0.0022097 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
0.150: [Full GC (System.gc()) 0.151: [SoftReference, 0 refs, 0.0001038 secs]0.152: [WeakReference, 4 refs, 0.0000127 secs]0.152: [FinalReference, 0 refs, 0.0000085 secs]0.152: [PhantomReference, 0 refs, 0 refs, 0.0000086 secs]0.152: [JNI Weak Reference, 0.0000103 secs][PSYoungGen: 560K->0K(76288K)] [ParOldGen: 8K->371K(175104K)] 568K->371K(251392K), [Metaspace: 2964K->2964K(1056768K)], 0.0065876 secs] [Times: user=0.03 sys=0.00, real=0.00 secs]
0.157: Total time for which application threads were stopped: 0.0092869 seconds, Stopping threads took: 0.0000445 seconds
Heap
PSYoungGen total 76288K, used 1966K [0x000000076ab00000, 0x0000000770000000, 0x00000007c0000000)
eden space 65536K, 3% used [0x000000076ab00000,0x000000076aceb9e0,0x000000076eb00000)
from space 10752K, 0% used [0x000000076eb00000,0x000000076eb00000,0x000000076f580000)
to space 10752K, 0% used [0x000000076f580000,0x000000076f580000,0x0000000770000000)
ParOldGen total 175104K, used 371K [0x00000006c0000000, 0x00000006cab00000, 0x000000076ab00000)
object space 175104K, 0% used [0x00000006c0000000,0x00000006c005ce08,0x00000006cab00000)
Metaspace used 2983K, capacity 4496K, committed 4864K, reserved 1056768K
class space used 327K, capacity 388K, committed 512K, reserved 1048576K
复制代码
上記のログからわかるように、このプロシージャは2回実行されgc
、どちらSystem.gc()
もそれによってトリガーされました。初めてgc
、若い世代のリサイクル状況が引き起こされました。6717K->568K
見られjvm
ないの両方として回収することなく、お互いを指す(ここでも2Mバイト配列のサイズを含む各オブジェクト)。また、現在の仮想マシンがカウンターを参照してオブジェクトが有効かどうかを判断していないことも示しています。
我々はここだけで2つのオブジェクトを生成することに気づいたいくつかの小さな友人があるかもしれない
objA
としてもobjB
。次に、ヒープメモリの回復はメモリ回復の4M
左右から開始する必要がありますが、リサイクルはなぜ6M
メモリから開始したのですか?===>ここではmain
、コンテナー内で実行されている関数ではなく、関数(静的メソッド)を実行していBean
ます。したがって、実行時に、メインクラスのインスタンスオブジェクトがヒープ上に生成されています。
到達可能性分析アルゴリズム
到達可能性分析アルゴリズム->「GCルート」と呼ばれる一連のオブジェクトを開始点として、これらのノードから開始して下に検索し、オブジェクトが「GCルート」に移動するときに、検索によってトラバースされるパスを参照チェーンと呼びます。 「参照チェーンが接続されていない場合は、このオブジェクトが使用できないことが証明され、リサイクルできます。以下に示すように:
上の画像にはroot
ノードが含まれています。つまり、基になるオブジェクトはまだ生きていますが、右側のサブツリーの上にあるオブジェクトはリサイクル可能と判断されます。
仮想マシンスタックでGCルートとして使用できるオブジェクトは次のとおりです。
- 仮想マシンのスタックで参照されるオブジェクト(スタックフレームのローカル変数テーブル)
- クラスの静的プロパティによって参照されるオブジェクトに移動するメソッド
- 定数によって参照されるオブジェクトに移動するメソッド
- ローカルメソッドスタックでJNI(一般にネイティブメソッド)によって参照されるオブジェクト
引用
上記の2つの回復アルゴリズムによるものかどうか、オブジェクトが存続するかどうかは「参照」に関連しています。
JDK1.2
以前はjava
、参照は次のように定義されていました。reference
データのタイプに格納された値が別のメモリの開始アドレスを表す場合、このメモリは参照を表すと言われています。次に、この定義によれば、オブジェクトには引用されている状態と引用されていない状態の2つしかありません。JDK1.2
その後拡張されました:強参照、弱参照、弱参照、およびファントム参照。
- 強い参照: "Object obj = new Object()"などの参照。強い参照がまだ存在している限り、ガベージコレクターは参照されたオブジェクトを再利用しません。
- ソフトリファレンス:有用であるが不要なオブジェクトについて説明します。ソフト参照に関連するオブジェクトの場合、これらのオブジェクトは、システムでメモリオーバーフロー例外が発生する前に、セカンダリリカバリのリカバリ範囲にリストされます。この回復に十分なメモリがない場合、メモリオーバーフロー例外がスローされます。(
JDK1.2
後で、SoftReference
ソフト参照を実装するためのクラスが提供されます)。 - 弱い参照:重要でないオブジェクトについて説明しますが、強度は弱い参照よりも弱いです。弱い参照に関連付けられているオブジェクトは、次のガベージコレクションが発生するまでしか存続できません。ガベージコレクターが機能する場合、現在のメモリが十分かどうかに関係なく、弱く参照されているオブジェクトのみが収集されます。(
JDK1.2
後で、WeakReference
弱参照を実装するためにクラスが提供されます)。 - 仮想参照:最も弱い参照関係です。オブジェクトに仮想参照があるかどうかは、生存時間にまったく影響を与えません。また、仮想参照を通じてオブジェクトインスタンスを取得することもできません。オブジェクトの仮想参照の関連付けを設定する唯一の目的は、このオブジェクトのガベージコレクターによってリサイクルされることですシステム通知を受け取りました。(
JDK1.2
後で、PhantomReference
仮想参照を実装するためのクラスが提供されます)。
対象の生存または死亡
上記の到達可能性分析アルゴリズムで到達できないオブジェクトは、必ずしも「死ぬ必要がある」わけではありません。一時的に「保護観察」段階にあります。オブジェクトの死を本当に宣言するには、少なくとも2つのマーキングプロセスが必要です。
- オブジェクトの到達可能性分析により、
GC Roots
参照チェーンが接続されていないことが検出されると、最初にマークが付けられ、このオブジェクトにfinalize()
メソッドが必要であるという条件でスクリーニングが実行されます。オブジェクトがこのメソッドをオーバーライドしない場合、またはこのメソッドが仮想マシンによって呼び出された場合、仮想マシンは両方のケースを「実行する必要がない」として扱います。 finalize()
メソッドの実行にオブジェクトが必要であると判断された場合、オブジェクトはというF-Queue
キューに配置されます。その後、仮想マシンは自動的Finalizer
に実行する低優先度のスレッドを作成します(このメソッドをトリガーするだけであり、実行の終了を待たずに実行が遅くなったり、循環システム全体がクラッシュする原因となる無限ループを防ぎます)。2番目のマークの間にオブジェクトが参照チェーン内のオブジェクトに再度関連付けられている限り、リサイクルを回避します。
デモ:
public class FinalizesxEscapeGC {
public static FinalizesxEscapeGC save = null;
public void isAlive() {
System.out.println("i am alive");
}
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("finalize executed");
save = this; // 为什么需要用到类的静态变量?
}
public static void main(String[] args) throws InterruptedException {
save = new FinalizesxEscapeGC();
// 对象第一次拯救自己
save = null;
System.gc();
Thread.sleep(500);
if (save != null) {
save.isAlive();
} else {
System.out.println("i am dead");
}
// 第二次拯救失败
save = null;
System.gc();
Thread.sleep(500);
if (save != null) {
save.isAlive();
} else {
System.out.println("i am dead");
}
}
}
复制代码
結果の出力:
finalize executed
i am alive
i am dead
复制代码
上記からDemo
わかるように、オブジェクトsave
は最初のガベージコレクションから脱出し、2回目に回収されました。オブジェクトのfinalize()
メソッドはシステムによって自動的に1回だけ呼び出され、2回目は呼び出されないためです。
リサイクル方法エリア
多くの人は、メソッド領域(永続的な生成)にガベージコレクションがないと考えています。
Java
仮想マシンの仕様では、この領域にガベージコレクションを実装するために仮想マシンを要求することはできず、この領域のガベージコレクション性价比
はそれほど高くありません。この領域には、ガベージコレクションの2つの主要な部分が废弃常量
あり无用的类
ます。
-
廃止さ
れた定数定数プール内の定数がどこにも参照されていない場合、この時点でメモリが回復し、必要に応じてシステムによって定数プールから定数がクリアされます。 -
役に立たないクラス
- このクラスのすべてのインスタンスはリサイクルされています。
- このクラスをロードしたClassLoaderはリサイクルされました。
- このクラスに対応するjava.lang.Classオブジェクトはどこからも参照されません。
リサイクルできるのは、上記の3つの条件を満たす不要なクラスだけです。ここでいうのは「缶」であり、対象物と同じではなく、使用しなければリサイクルされます。
この記事では、JVMでオブジェクトが生きているか死んでいるかを判断する問題を簡単に紹介するだけでなく、2種類のリサイクルアルゴリズムと、オブジェクトが生きているかどうかを判断する問題も紹介します。次の記事は、ガベージコレクションアルゴリズムと併せて詳しく説明します。
抜粋:「Java仮想マシンの詳細な理解」