I.概要
Java仮想マシンを深く理解すると、「JavaとC ++の間には、動的メモリ割り当てとガベージコレクションテクノロジに囲まれた高い壁があります。壁の外側の人は入りたいが、壁の内側の人は出たいと思っています。 「」
Javaは、動的メモリ割り当てとリサイクルですでに自動化されていますが、さまざまなメモリオーバーフローやメモリリークのトラブルシューティングが必要な場合、ガベージコレクションがシステムの同時実行性を高めるためのボトルネックになると、これらを「自動化」する必要があります。必要な監視と調整。
1.1ゴミとは
ガベージとは、実行中のプログラムにポインタがないオブジェクトを指します。このオブジェクトは、リサイクルが必要なガベージです。メモリ内のガベージが時間内にクリーンアップされない場合、これらのガベージオブジェクトによって占有されているメモリスペースは、アプリケーションが終了するまで残り、予約されたスペースを他のオブジェクトが使用することはできません。メモリオーバーフローを引き起こす可能性さえあります。
1.2メモリオーバーフローまたはメモリリーク
- メモリオーバーフロー:プログラムがスペースを申請しているときに、メモリが不足し、oom例外が発生します。たとえば、プレートは5つのリンゴしか保持できず、6つのリンゴを強制的に与えるとメモリオーバーフローが発生します。
- メモリリーク:プログラムがメモリスペースを申請しているとき、申請されたスペースを解放できません。複数のメモリリークが発生すると、重大なメモリ問題が発生します。たとえば、キャビネットのキーがキャビネットにロックされている場合、キャビネットの内容にアクセスできません。
1.3ガベージコレクションエリア
頻度の観点から、ヒープ領域でのガベージコレクションの重要な領域:
- ヤングエリアの頻繁な収集
- 古いエリアのコレクションが少ない
- 基本的に動かないパーマエリア
2.オブジェクトがゴミかどうかを判断します
2.1参照カウント方法
オブジェクトに参照カウンターを追加します。オブジェクトへの参照がある場合は常に、カウンターの値が1増加し、参照が無効な場合は、カウンターの値が1減少します。
参照カウントを使用すると循環参照が発生するため、このメソッドはJavaでは使用されません。たとえば、次のコードを見てください。
public class ReferenceCountingGC {
public ReferenceCountingGC instance = null;
private Byte[] bytes = new Byte[1024 * 1024];
public static void main(String[] args) {
ReferenceCountingGC A = new ReferenceCountingGC();
ReferenceCountingGC B = new ReferenceCountingGC();
A.instance = B;
B.instance = A;
A = null;
B = null;
System.gc(); //手动进行GC
}
}
-XX:+ PrintGCDetailsパラメーターを追加して、GC情報を印刷します
循環参照があってもGCを実行できるため、このマーキング方法はJavaでは使用されていないことがわかります。
2.2ルート検索アルゴリズム
このアルゴリズムの基本的な考え方は、「GC Roots」という名前の一連のオブジェクトを開始点として使用し、これらのノードから開始して下向きに検索することです。検索によってたどるパスは、参照チェーンと呼ばれます。オブジェクトがGCルートが参照チェーンによって接続されていない場合(グラフ理論の言葉では、GCルートからオブジェクトに到達できない場合)、オブジェクトが使用できないことを証明します。
たとえば、上の図では、object5、object6、object7は到達不能オブジェクトと判断され、ガベージと見なされます。
次に、GCルートと判断されたオブジェクトには次のものが含まれます。
- 仮想マシンスタック内の参照オブジェクト
- メソッド領域のクラスの静的プロパティによって参照されるオブジェクト
- メソッド領域の定数によって参照されるオブジェクト
- ローカルメソッドスタック内の参照オブジェクト
2.3ファイナライズメカニズム
Java言語は、オブジェクトが破棄される前に開発者がカスタム処理ロジックを提供できるようにするオブジェクトファイナライズメカニズムを提供します。ガベージコレクターがオブジェクトへの参照がないことを検出した場合、つまり、オブジェクトがガベージコレクションされる前に、finalize()メソッドがあり、それが呼び出されていない場合、ガベージコレクターは常にのfinalize()メソッドを呼び出します。最初にオブジェクト。
このオブジェクトを実行する必要がある場合は、finalizeメソッド。次に、このオブジェクトがfinalize()メソッドの実行に必要であると判断された場合、このオブジェクトはF-Queueという名前のキューに配置され、後で仮想マシンによって自動的に作成され、優先度の低いファイナライザーで実行されます。スレッド。finalizeメソッドの実行時にオブジェクトをGCルート参照チェーンに戻すことができるため、オブジェクトが復活する可能性があります。
public class FinalizeEscapeGC {
private static FinalizeEscapeGC finalizeEscapeGC = null;
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("finalize method invoke");
//重新获得引用 对象复活
FinalizeEscapeGC.finalizeEscapeGC = this;
}
public static void main(String[] args) throws InterruptedException {
finalizeEscapeGC = new FinalizeEscapeGC();
finalizeEscapeGC = null;
System.gc();
//线程休眠 让步给finalize线程
Thread.sleep(500);
if(finalizeEscapeGC == null){
System.out.println("finalizeEscapeGC is not alive");
}else{
System.out.println("finalizeEscapeGC is still alive");
}
//只调用一次finalize方法
finalizeEscapeGC = null;
System.gc();
Thread.sleep(500);
if(finalizeEscapeGC == null){
System.out.println("finalizeEscapeGC is not alive");
}else{
System.out.println("finalizeEscapeGC is still alive");
}
}
}
注:オブジェクトのfinalizationメソッドは1回だけ呼び出されます!
3、ガベージコレクションアルゴリズム
3.1マークスイープアルゴリズム
アルゴリズムは、マーキングとクリアの2つの段階に分かれています。マーキング段階では、前のアルゴリズムを使用して、オブジェクトがガベージであるかどうかを判断します。ガベージをマーキングした後、次の図に示すように、マークされたすべてのオブジェクトが統一された方法で収集されます。
利点:これはポストオーダーアルゴリズムの基礎であり、アルゴリズムの実装は比較的簡単です
短所:
- 時間の問題:あまり効率的ではありません
- スペースの問題:マークがクリアされた後、多数の不連続なメモリフラグメントが生成され、大きなオブジェクトを割り当てる必要がある場合、スペースの断片化が多すぎるとスペースがなくなります。
3.2コピーアルゴリズム
使用可能なメモリを容量に応じて同じサイズの2つの部分に分割し、一度に1つだけを使用します。このメモリブロックが使い果たされると、残っているオブジェクトが別のブロックにコピーされ、使用されたメモリスペースがすぐにクリーンアップされます。このようにして、毎回1つのメモリが再利用され、メモリが割り当てられるときにメモリの断片化などの複雑な状況を考慮する必要がありません。
利点:
- マーキングと除去のプロセスがなく、簡単な実装と効率的な操作
- 過去をコピーした後、スペースの連続性を確認してください。「断片化」の問題は発生しません。
短所:
- メモリスペースをメモリの半分に減らしました
- 残っているオブジェクトが多い場合は、多数のオブジェクトをコピーする必要があります
レプリケーションアルゴリズムは通常、新世代をリサイクルするために使用されます
3.3マーキング-整理
最初のステップはマークスイープアルゴリズムと同じですが、次のステップは、再利用可能なオブジェクトを直接クリーンアップするのではなく、残っているオブジェクトを一方の端に移動してから、端の境界の外側のメモリを直接クリーンアップすることです。
利点:
- マーククリアアルゴリズムの分散メモリ領域の欠点を排除します。新しいオブジェクトにメモリを割り当てる必要がある場合、JVMはメモリの開始アドレスのみを保持する必要があります。
- コピーアルゴリズムでメモリを半分にする高コストを排除します
短所:
- 効率の点では、マークからソートへのアルゴリズムはコピーアルゴリズムよりも低くなります。
- オブジェクトの移動中に、オブジェクトが他のオブジェクトによって参照されている場合は、参照されているアドレスも調整する必要があります。・移動中は、プロセス全体でユーザーアプリケーションを一時停止する必要があります。すなわち:STW
3.4世代別収集アルゴリズム
最良のアルゴリズムはなく、より良いアルゴリズムのみがあります。以前のアルゴリズムには独自の長所と短所があるため、世代別収集アルゴリズムがあります。
まず、オブジェクトごとにライフサイクルが異なるため、異なる期間のオブジェクトに対して異なる収集アルゴリズムを使用できます。Javaヒープは若い世代と古い世代に分けられ、の特性に応じて異なるリサイクルアルゴリズムを使用できます。年齢ごと。リサイクルの効率を向上させるために
若い世代の特徴は、古い世代に比べて面積が比較的小さく、対象物のライフサイクルが短く、生存率が低く、リサイクルが多いことです。したがって、コピーアルゴリズムは若い世代で採用されており、コピーアルゴリズムのメモリ使用率が低いという問題は、ホットスポットでの2人の生存者の設計によって軽減されます。
老年期、老年期は、大きな記憶領域、長いオブジェクトのライフサイクル、および高い生存率によって特徴付けられます。一般に、マークスイープアルゴリズムまたはマークソートアルゴリズムのハイブリッド実装が採用され、GCが異なれば実装も異なります。
第四に、ガベージコレクター
ガベージコレクションアルゴリズムはアイデアであり、特定のガベージコレクターはこれらのアイデアの実践者です。jdkバージョンの継続的な更新の過程で、ガベージコレクターのテクノロジは常に更新され、繰り返されます。ここでは、jdk8より前の従来のガベージコレクターのみを紹介し、以降のバージョンで表示されるガベージコレクターを新機能で紹介します。対応するバージョンの。
4.14つの方法
jdk8には7種類のガベージコレクターがあり(後で説明しません。すべてのバージョンはjdk1.8です)、これらの7種類は4つの方法に分けることができます。
- シリアルガベージコレクター(シリアル)
- パラレルガベージコレクター(パラレル)
- コンカレントガベージコレクター(CMS)
- G1ガベージコレクター
4.1.1シリアルガベージコレクター(シリアル)
- ガベージコレクションにシングルスレッドを使用する
- 排他的なガベージコレクション。
シリアルコレクターがガベージコレクションを実行する場合、Javaアプリケーションのスレッドを一時停止(STW)し、ガベージコレクションの完了を待つ必要があります。これにより、ユーザーエクスペリエンスが低下します。
4.1.2並列ガベージコレクター(並列)
- ガベージコレクションにマルチスレッドを使用する
- 排他的なガベージコレクション
Parallel Garbage Collector(Parallel)は、主にマルチコアCPUで使用され、強力な同時実行性を備えています。シリアルガベージコレクターと同様に、Javaアプリケーションは動作時に停止する必要がありますが、一時停止時間はシリアルガベージコレクターよりも長くなります。ただし、シングルスレッドのシングルコアCPUの場合、そのパフォーマンスはシリアルガベージコレクタよりも悪い可能性があります
4.1.3コンカレントガベージコレクター(CMS)
CMSは、Concurrent Mark Sweepの略語で、Concurrent Mark Sweepを意味します。名前から、マークスイープアルゴリズムを使用していることがわかります。CMSコレクターが動作している場合、Javaアプリケーションの実行が許可されますが、特定の手順で実行されます。 CMSの一部の手順では、Javaアプリケーションを実行できません。だが
全体として、CMSは排他的ではありません
4.1.4G1ガベージコレクター
G1コレクターの目標は、サーバーのガベージコレクターになることです。したがって、スループットと一時停止制御の点で、CMSコレクターよりも優れたパフォーマンスが期待されます。CMSコレクターと比較すると、G1コレクターはマーク圧縮アルゴリズムに基づいています。したがって、スペースフラグメントは生成されず、収集の完了後に排他的な最適化を実行する必要はありません。G1コレクターは、非常に正確な一時停止制御も実行できます
4.2クラシックガベージコレクター
スコープの分類により、新世代のガベージコレクター、旧世代のガベージコレクター、G1コレクターの7種類のガベージコレクターに分類できます。
-
新世代のガベージコレクター:
- シリアルコレクター
- ParNewコレクター
- パララースカベンジコレクター
-
老後のガベージコレクター:
- CMSコレクター
- シリアルオールドコレクター
- パララーオールドコレクター
-
G1コレクター
図は、異なる世代で動作する7種類のコレクターを示しています。2つのコレクターが接続されている場合は、それらを一緒に使用できることを意味します。図のコレクターの位置は、新しい世代に属していることを示しています。コレクター。それとも老後のコレクターですか。
4.2.1シリアルコレクター(新世代)
シリアルコレクターはシングルスレッドのガベージコレクターです。ガベージコレクション中は、次の図に示すように、コレクションが終了するまで他のすべてのワーカースレッド(STW)を一時停止する必要があります。
シリアルコレクターは、最も基本的で最も古いガベージコレクターであり、最も安定していて最も効率的なコレクターでもあります。シリアルコレクターまたはJVM仮想マシンが実行されているクライアントモードの場合デフォルトの若い世代のガベージコレクタ。
ここで注意してください:それはクライアントモードであり、現在のマシンのほとんどはサーバーモードです
対応するパラメーターを使用して、シリアルコレクターを強制的にオンにすることもできます。JVMパラメーターは次のとおりです。
- -XX:+ UseSerialGC
ただし、JVMは世代別収集アルゴリズムを使用するため、-XX:+ UseSerialGCを使用して新しい世代を開くのはシリアルコレクターであるため、古い世代はデフォルトでシリアル古いコレクターの組み合わせを使用することに注意してください。
//-Xms10m -Xmx10m -XX:+PrintGCDetails -XX:+PrintCommandLineFlags -XX:+UseSerialGC
public static void main(String[] args) throws InterruptedException {
System.out.println("*************");
Byte[] bytes = new Byte[50 * 1024 * 1024];
}
4.2.2 ParNewコレクター(新世代)
ParNewコレクターは、基本的にシリアルコレクターのマルチスレッド並列バージョンです。最も一般的なアプリケーションシナリオは、古いCMSのGC作業と連携することです。残りは、シリアルコレクターと同じです。ParNewコレクターも必要です。ガベージコレクションプロセス中に中断されました。他のすべてのワーカースレッド。これは、サービスモードで実行されている多くのJava仮想マシンの新世代のデフォルトのガベージコレクターです。
パラメータをオンにします。
- -XX:+ UseParNewGC
上記のパラメーターを使用する場合、新しい世代はParNewコレクターを使用し、古い世代はSerial Oldコレクターを使用しますが、出力コンソールも上の図に示すように赤いログを出力します。一般的な考え方は、ParNew + Serial Oldの組み合わせは、初期接続図に対応する将来のバージョンでキャンセルされるというものです。ParNew+ Serial Oldの組み合わせは、jdk9バージョンでは推奨されなくなり、キャンセルされました。 -XX:+ UseParNewGCパラメーターを直接
4.2.3 Paraller Scavengeコレクター(新世代)
Paraller ScavengeコレクターはParNewに似ており、新世代のガベージコレクターでもあります。レプリケーションアルゴリズムを使用し、マルチスレッドの並列ガベージコレクターです。ただし、Paraller ScavengeとParNewの違いは、ParallerScavengeの目標が達成することです。制御可能なスループット。、スループットの定義は次のとおりです。
スループット=ユーザーコードを実行する時間/(ユーザーコードを実行する時間+ガベージコレクションを実行する時間)
Paraller Scavengeコレクターの適応調整戦略も、ParNewコレクターとの重要な違いです。つまり、仮想マシンは現在のシステム操作に従ってパフォーマンスモニタリング情報を収集し、これらのパラメーターを動的に調整して、適切な一時停止時間または最大スループットを提供します。
パラメータをオンにします。
- -XX:+ UseParallerGC
jdk1.8サーバーの環境では、デフォルトのガベージコレクターは、新世代のParallerScavengeコレクターと旧世代のParallerOldコレクターです。
上の画像は、-XX:+ UseParallerGCパラメーターを使用せずに出力された情報です。デフォルトで使用されるガベージコレクターはParallerScavenge + ParallerOldであることがわかります。
Paraller Scavengeコレクターには、適応的に調整されたパラメーターがいくつかあります。
-
-XX:MaxGCPauseMillis:ガベージコレクションの最大一時停止時間を制御します。このパラメーターの値は0msより大きくする必要がありますが、このパラメーターの時間調整によってシステムのガベージコレクション速度が速くなるわけではありません。ガベージコレクションの一時停止時間は、スループットと新しい生成スペースを犠牲にして短縮されます。
-
-XX:GCTimeRatio:スループットサイズを設定します。これは、0より大きく100より小さい整数、つまり、合計時間に対するガベージコレクション時間の比率であり、スループットの逆数に相当します。たとえば、この場合パラメータは19に設定され、許可される最大ガベージコレクション時間は合計時間の5%(つまり、1 /(1 + 19))を占め、デフォルト値は99で、最大1%(つまり、1 / (1 + 99))ガベージコレクション時間
4.2.4シリアルオールドコレクター(旧世代)
Serial Oldコレクターは、Serialコレクターの古いバージョンであり、マークアンドソートアルゴリズムを使用するシングルスレッドコレクターでもあります。このコレクターの主な意味は、クライアントモードのHotSpot仮想マシンにもあります。
サーバーモードの場合は、2つの目的もあります。1つはJDK5以前のバージョンのParallelScavengeコレクターで使用すること、もう1つはCMSコレクターに障害が発生した場合のバックアッププランとして使用することです。コレクションは、コンカレントモード障害が発生したときに使用されます。
開始パラメータはシリアルコレクタと同じです
4.2.5 Paraller旧コレクター(旧世代)
Parallel Oldは、Parallel Scavengeコレクターの古いバージョンであり、マルチスレッドの同時収集をサポートし、マークソートアルゴリズムに基づいています。
4.2.6 CMSコレクター(旧世代)
CMS(Concurrent Mark Sweep)コレクターは、最短のリカバリー休止時間を取得することを目的としたコレクターです。現在、Javaアプリケーションの大部分はインターネットWebサイトやブラウザベースのB / Sシステムのサーバー側に集中しています。このようなアプリケーションは通常、サービスの応答速度に注意を払い、システムの一時停止時間ができるだけ短いことを望んでいます。可能な限りユーザーに優れたインタラクティブエクスペリエンスを提供します。CMSコレクターは、このタイプのアプリケーションのニーズに非常に適しています。
CMSコレクターは4つの段階に分かれています。
- 初期マーク:初期マークはこの段階ではまだSTWですが、初期マークは、GCルートが直接関連付けることができるオブジェクトをマークするためだけのものです(到達可能性分析アルゴリズム)。
- 同時マーキング:同時マーキングとは、オブジェクトグラフ全体をトラバースして、最初にマークされたオブジェクトからガベージを見つけるプロセスを指します。この段階には長い時間がかかりますが、ユーザースレッドを一時停止する必要はありません。
- 再マーキング:再マーキングは、並行プロセスのために前のステージでユーザースレッドによって生成されたオブジェクトをマークすることです。このステージはまだSTWです。
- 同時クリーンアップ:マーキングフェーズでデッドと判断されたガベージオブジェクトをクリーンアップします。このプロセスは、ユーザースレッドと同時に実行することもできます。
上記の4つの段階から、CMSコレクターは、より時間のかかる段階でユーザースレッドと並列化できることがわかります。したがって、全体として、CMSのメモリガベージコレクションプロセスはユーザースレッドと同時に実行されます。
パラメータをオンにします。
- -XX:+ UseConcMarkSweepGC
-XX:+ UseConcMarkSweepGCが設定されている場合、JVMはParNew + CMSの組み合わせを使用することがわかります。
短所:
-
CMSコレクターはCPUリソースに非常に敏感です。これは、並行フェーズでユーザースレッドの一部を占有する必要があると、アプリケーションの速度が低下し、合計スループットが低下するためです。この状況を緩和するために、仮想マシンはメソッドを提供します。 「インクリメンタル同時実行」と呼ばれます。「コレクター」(インクリメンタル同時マークスイープ/ i-CMS)はCMSコレクターの変形です。これは、マルチコア並列をシミュレートするプリエンプティブマルチタスクのアイデアと同じです。シングルコアプロセッサ時代のPCオペレーティングシステムによるマルチタスク同時マーキングとクリーニング中に、コレクタスレッドとユーザースレッドを交互に実行して、ガベージコレクションスレッドの排他的リソースの時間を最小限に抑え、ガベージコレクション全体を最小限に抑えることができます。プロセスは長くなりますが、ユーザープログラムへの影響は少なくなります。直感的には、速度が遅くなる時間が長くなりますが、速度の低下はそれほど明白ではありません。
-
CMSコレクターが並行フェーズで動作している場合、ユーザースレッドが再びガベージを生成する可能性があるため、CMSコレクターはフローティングガベージを処理できません。その結果、今回生成されたガベージは次回のみクリーンアップできます。
-
CMSコレクターは、マークスイープアルゴリズムに基づくコレクターであり、多くのスペースの断片化を生成します。
4.2.7G1ガベージコレクター
G1ガベージコレクターは、以前の6つのコレクターにとって画期的な変更です。以前のガベージコレクターは次のとおりです。
- 若い世代と古い世代は独立した連続したメモリブロックです
- 若い世代のコレクションはレプリケーションアルゴリズムを使用しています
- 古い世代のコレクションは、古い世代の領域全体をスキャンする必要があります
G1ガベージコレクターはサーバー指向のコレクターであり、その設計目標はCMSコレクターを置き換えることです。したがって、G1ガベージコレクターにはCMSコレクターの利点がありますが、CMSコレクターと比較すると、次の側面があります。パフォーマンスが向上します。
- G1コレクターは多くのメモリの断片化を生成しません
- G1のSTWはより制御可能であり、予測メカニズムが一時停止時間に追加され、ユーザーは予想される一時停止時間を指定できます
以前のガベージコレクターは、連続メモリスペースを新世代と旧世代のメタスペースに分割します。この分割の特徴は、割り当てられたメモリが連続していることです。
ただし、G1コレクターの各世代のストレージスペースは不連続です。各世代は同じサイズのn個の不連続領域を使用します。各領域は連続メモリアドレスを占有します。つまり、G1はメモリスペースをのすべてのA領域に分割します。同じサイズの場合、これらの領域は新世代または旧世代を格納できます
さらに、上の図の一部の領域にはHが付いています。これは、Humongousの略で、これらの領域に巨大なオブジェクトが格納されていることを意味します。
G1ガベージコレクターは4つのステップに分かれています。
-
初期マーク:GCルートが直接関連付けることができるオブジェクトのみをマークし、ユーザースレッドを一時停止する必要があります
-
同時マーキング:GCルートから開始して、ヒープ内のオブジェクトの到達可能性分析を実行し、ヒープ全体のオブジェクトグラフを再帰的にスキャンして、リサイクルするオブジェクトを見つけます。この段階には時間がかかりますが、ユーザープログラムと同時に実行できます。オブジェクトグラフのスキャンが完了した後、同時実行中に参照が変更されたSATBによって記録されたオブジェクトを再処理する必要があります
-
最終マーク:同時マークの修正中に、プログラムの実行によりマークが変更されたオブジェクトの部分は、ユーザースレッドを一時停止する必要があります
-
スクリーニングとリサイクル:リサイクルの価値を最大化するための時間に応じて
パラメータをオンにします。
- -XX:+ UseG1GC
616632107059)]
さらに、上の図の一部の領域にはHが付いています。これは、Humongousの略で、これらの領域に巨大なオブジェクトが格納されていることを意味します。
G1ガベージコレクターは4つのステップに分かれています。
-
初期マーク:GCルートが直接関連付けることができるオブジェクトのみをマークし、ユーザースレッドを一時停止する必要があります
-
同時マーキング:GCルートから開始して、ヒープ内のオブジェクトの到達可能性分析を実行し、ヒープ全体のオブジェクトグラフを再帰的にスキャンして、リサイクルするオブジェクトを見つけます。この段階には時間がかかりますが、ユーザープログラムと同時に実行できます。オブジェクトグラフのスキャンが完了した後、同時実行中に参照が変更されたSATBによって記録されたオブジェクトを再処理する必要があります
-
最終マーク:同時マークの修正中に、プログラムの実行によりマークが変更されたオブジェクトの部分は、ユーザースレッドを一時停止する必要があります
-
スクリーニングとリサイクル:リサイクルの価値を最大化するための時間に応じて
[外部リンク画像が転送されています...(img-1YDMKNeH-1616632107060)]
パラメータをオンにします。
- -XX:+ UseG1GC