この記事では主に、Javaランタイムデータ領域、オブジェクト作成、ガベージコレクションアルゴリズム、リサイクル戦略を含む、Javaのメモリ割り当てとリサイクルメカニズムについて説明します。
PHP中国語Webサイト講座「JAVA初級入門ビデオチュートリアル」を参考に、チュートリアルの内容を元に筆者が要約して図解しただけです。内容のこの部分は、理解と記憶を容易にするために、可能な限り図、テキスト、または表の形式で提示されます。
次の図は、実行時の Java 仮想マシンのメモリ図です:
この図から、Java メモリが次のように分割されていることがわかります。 6 つの部分:
プログラム カウンター: 各スレッドには独立したプログラム カウンターがあります、 このカウンターは、現在のスレッドによって実行されるバイトコードの行番号インジケーターとして見ることができます。バイトコード インタプリタが動作すると、このカウンタの値を変更して、実行する次のバイトコード命令、分岐、ループ、ジャンプ、例外処理、およびスレッド回復などの基本的な機能はすべてこのカウンタに依存します。完了です。
Java 仮想マシン スタック: 仮想マシン スタックはスレッドに対してプライベートであり、ライフ サイクル はスレッドと同じです。仮想マシン スタックは、Java メソッド実行のメモリ モデル を記述します。各メソッドが実行されると、ローカル 変数 テーブル、オペランド スタック、ダイナミック リンク、メソッド出口などの情報を保存するためのスタック フレームが作成されます。 各メソッドの呼び出しから実行完了までの処理は、スタックフレームを仮想マシンのスタックにプッシュしてからポップアウトするまでの処理に相当します。
ローカル メソッド スタックはネイティブ メソッド を提供することです。
すべてのスレッドによって共有される領域。仮想マシンの起動時に作成され、ほぼすべてのオブジェクト インスタンスがヒープ上に割り当てられます。 Java ヒープは、新世代と旧世代にさらに分割することもできます。詳しくは、Eden 空間、From Survivor 空間、To Survivor 空間があります。ただし、どのように分割しても、すべてのオブジェクト インスタンスは保存されます。さらに分割する目的は、メモリをより適切に再利用したり、メモリをより速く割り当てたりすることです。
メソッド領域は各スレッドが共有するメモリ領域で、主に仮想マシンがロードするクラス情報、定数、静的変数、ジャストインなどのデータを格納するために使用されます。 -time コンパイルされたコード。 この領域は、Java ヒープと同様、連続メモリを必要とせず、固定または拡張可能であり、ガベージ コレクションを実装しないことも選択できます。この領域のメモリ リサイクル ターゲットは主に定数プールのリサイクルと型のアンロードのためであり、この領域ではガベージ コレクション 動作 はほとんど発生しません。
クラスクラスのバージョン、フィールド、メソッド、インターフェースなどの説明情報に加えて、コンパイル中に生成されるさまざまなリテラルやシンボル参照を保存するために使用される定数プールもあります。コンテンツの一部は、クラスがロードされた後、メソッド領域のランタイム定数プールに保存されます。
。 NIO クラスは、JDK1.4 の後に導入されました。これは、チャネルとバッファーに基づく I/O メソッドであり、Nativefunctionライブラリを使用してヒープの外にメモリを直接割り当て、それを Java ヒープの DirectByteBuffer に保存できます。オブジェクトは、このメモリを操作するための参照として使用されます。これにより、パフォーマンスが大幅に向上し、Java ヒープとネイティブ ヒープの間でのデータの往復コピーが回避されます。
データ領域 | 概要 | スレッド共有 |
---|---|---|
プログラムカウンター | 現在のスレッドによって実行されたバイトコードの行番号インジケーター | いいえ |
仮想マシンスタック | Javaメソッド実行用ローカル変数、オペランド スタック、ダイナミック リンク、メソッド出口、その他の情報を保存するスタック フレームを作成します | いいえ |
ローカル メソッド スタック | 仮想マシン スタックと同様に、ネイティブ メソッドを提供します | いいえ |
スタック | オブジェクト インスタンスを格納します | は |
メソッド領域です | ロードされたクラス情報、定数、静的変数、オンザフライでコンパイルされたコード、および仮想マシンのその他のデータを格納します | は |
ランタイム定数プール | コンパイル中に生成されたリテラルとシンボル参照を格納するメソッド領域の一部 | は、 |
ヒープの外に割り当てられたダイレクトメモリ | メモリであり、パフォーマンスが高く、Javaのサイズによって制限されませんヒープ | は |
上の図はオブジェクト作成の完全なフローチャートであり、以下で詳しく説明します。
仮想マシンがnew命令を受け取ると、この命令のパラメータが定数プール内のクラスのシンボリック参照を見つけられるかどうかをチェックし、このシンボリック参照によって表されるクラスがロードされているかどうかをチェックします。そして解析され初期化されます 。そうでない場合は、クラスのロード プロセスを最初に実行する必要があります。
クラスのロードが完了すると、オブジェクトの割り当てに必要なスペースを決定できます。 Java ヒープ内のメモリが完全に規則的で、一方の側に使用済みメモリが保存され、もう一方の側に空きメモリが保存され、境界点のインジケータとして中央にポインタがある場合、メモリの割り当ては単に移動するだけです。ポインタを一定量だけ空き領域に向けて配置します。この配置方法は「ポインタ衝突」と呼ばれます。 Java ヒープ内のメモリが規則的ではなく、空きメモリと使用済みメモリがインターリーブされている場合、仮想マシンは使用可能なメモリ ブロックを記録するリストを維持し、オブジェクト インスタンスとメモリを割り当てるときに、リストから割り当てる十分な領域を見つけ出す必要があります。 リストのレコードを更新します。この割り当て方法は「フリーリスト」と呼ばれます。どの割り当て方法が使用されるかは、通常、仮想マシンのガベージ コレクターにコンパクション機能があるかどうかによって決まります。
セーフであるかどうかも考慮する必要があります。スレッドの安全性を確保するには、2 つのオプションがあります。 1 つは、メモリ領域を割り当てるアクションを同期することです。実際、仮想マシンは更新操作のアトミック性を確保するために、失敗による再試行を伴う CAS を使用します。もう 1 つは、メモリ割り当てアクションをスレッドごとに異なる領域に分割することです。各スレッドは、ローカル スレッド割り当てバッファ(スレッド ローカル割り当てバッファ、TLAB) と呼ばれる、Java ヒープ内の小さなメモリを事前に割り当てます。メモリを割り当てたいスレッドは、そのスレッドの TLAB にメモリを割り当てます。同期ロックは、TLAB が使い果たされ、新しい TLAB が割り当てられる場合にのみ必要になります。
メモリ割り当てが完了すると、仮想マシンは仮想マシンは、オブジェクトの
実行時データ を保存するために使用されます。偏ったスレッドID、偏ったタイムスタンプなど。
もう 1 つの部分は Java 仮想マシンは、到達可能性分析 を通じてオブジェクトが生存しているかどうかを判定します。このアルゴリズムの基本的な考え方は、「GC ルート」と呼ばれる一連のオブジェクトを開始点として使用し、オブジェクトが GC ルートに到達したときにこれらのノードから下方向に探索するパスを参照チェーンと呼びます。参照がない場合、チェーンが接続されている間、オブジェクトは使用できません。 図に示すように、object
5、object6、object7は相互に関連していますが、GCルートに到達できないため、再利用可能なオブジェクトと判断されます。 もう 1 つ言及する価値があるのは、参照カウント メソッドでは、オブジェクトへの参照があるたびにカウンター値が 1 ずつ増加し、参照が失敗するとカウンター値が 1 ずつ減少します。 1 つ; いつでも カウンタが 0 のオブジェクトは使用できなくなります。参照カウンターは効率的で実装が簡単です。ただし、オブジェクト間の循環参照の問題を解決するのは困難です。ほとんどすべての主流の Java 仮想マシンは、メモリの管理に参照カウントを使用しなくなりました。
到達可能性分析の概念図
到達可能性分析アルゴリズムで到達不可能なオブジェクトであっても、すぐに再利用されない場合があります。オブジェクトをリサイクルする場合、少なくとも 2 回マーキング プロセスを通過する必要があります。
このオブジェクトが Finalize() メソッドの実行に必要であると判断された場合、オブジェクトは F-Queue
キューに配置され、その後、優先度
の低いファイナライザー スレッドが仮想マシンによって自動的に作成されますFinalize() メソッドを実行します。 GC は、F キュー内のオブジェクトに対して 2 回目の小規模マークを実行します。そのオブジェクトが参照チェーン上のいずれかのオブジェクトに再度関連付けられると、そのオブジェクトは 2 回目のマーク中に「すぐにリサイクルされる」コレクションから削除されます。 。そうしないと、オブジェクトは実際にリサイクルされてしまいます。
メソッドのファイナライズ
2. メソッド領域のリサイクルの決定
の2つの部分が含まれます。 破棄された定数のリサイクルは、Java ヒープ内のオブジェクトのリサイクルに似ています。
役に立たないクラスを判断するための条件は、次の 3 つの条件を満たす必要があります:
スペースの問題です。マークがクリアされた後、大量の不連続なメモリ フラグメントが生成されるため、より大きなオブジェクトが割り当てられたときにメモリ スペースが不足する可能性があり、ガベージ コレクション アクションが必要になります。事前に発動される。
マーククリア
に削減され、その分コストが高くなります。
Mark-Compact(Mark-Compact)
:
マーキングプロセスは「マーククリア」アルゴリズムと同じですが、その後のリサイクル可能なオブジェクトのクリーニングは異なります直接実行されますが、すべての生きているオブジェクトを一方の端に移動させ、端の境界の外側のメモリを直接クリーンアップします
4.世代別コレクション アルゴリズム
のガベージ コレクション商用仮想マシン 世代別コレクション アルゴリズムを使用して、オブジェクトの生存サイクルに従ってメモリをいくつかのブロックに分割します。 Javaヒープは新世代と旧世代
オブジェクトは Eden パーティションで優先されます:
ラージ オブジェクトは古い世代に直接入ります:
長期的に存続するオブジェクトは古い世代に入ります:
動的な年齢判断:
スペース割り当ての保証:
新世代 GC (マイナー GC): 新世代で発生するガベージ コレクション アクション。ほとんどの Java オブジェクトは生成されて消滅するため、マイナー GC は非常に頻繁に発生し、リサイクル速度も高速です。
旧世代 GC (メジャー GC/フル GC): 旧世代で発生するガベージ コレクション アクション。メジャー GC には、少なくとも 1 つのマイナー GC が伴うことがよくあります。メジャー GC の速度は、通常、マイナー GC よりも 10 倍以上遅くなります。
🎜以上がJava メモリの割り当てとリサイクルのメカニズムの詳細な説明 (図)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。