Java メモリ領域とメモリ オーバーフロー
Java 仮想マシンのメモリ割り当て図:
各領域の特性を次の表にまとめます:
追加説明:
マルチスレッド状況では、スレッドがヒープにメモリを割り当てる場合、メモリ割り当ての同期の問題が発生する可能性があります。1 つはメモリ割り当てアクションを同期する方法で、もう 1 つは少量のメモリを事前に割り当てることを意味します。 Java ヒープ内の各スレッドのブロック スレッドプライベート ローカル スレッド割り当てバッファ。このようにして、スレッドがメモリを割り当てる必要がある場合、スレッドは独自の TLAB 上で割り当てを行うため、同期のオーバーヘッドが回避されます。ただし、TLAB が完全に割り当てられ、再割り当てされた場合でも同期は必要です。
クラスが不要なクラスであるかどうかを判断するには、次の条件が必要です。 1. クラスのすべてのインスタンスがリサイクルされている。クラスの ClassLoader はリサイクルされています。 3 このクラスの java.lang.Class オブジェクトはどこにも参照されていません。リサイクルは可能であり、リサイクルはできないことに注意してください。
メモリ割り当て方法: 仮想マシンで使用される方法は、メモリが正規かどうかによって決まり、メモリが正規かどうかはリサイクル アルゴリズムによって決まります。
ポインタの衝突: 割り当てられたすべてのメモリが一方の側に配置され、空きメモリがもう一方の側に配置されると仮定します。メモリを割り当てる必要がある場合、ポインタのみが必要になります。この方法はポインタ衝突と呼ばれます。このメソッドは、Serial、ParNew、および Compact を備えた他のリサイクル業者によって使用されます
フリー リスト: 仮想マシンに割り当てられたメモリと空きメモリは規則的ではなく、相互に絡み合っているため、どのメモリを表すリストを維持する必要がありますが利用可能であり、メモリを割り当てる必要がある場合は、リストをクエリして利用可能なメモリ サイズを見つける必要があります。このアプローチはフリーリストと呼ばれます。このメソッドは、マークスイープ アルゴリズムに基づいて CMS および他のリサイクル業者によって使用されます。HotSpot 仮想マシン内のオブジェクトのメモリ レイアウトは、次の表に示すとおりです。
Java 仕様では、参照型は 1 つだけです。オブジェクトへの参照が指定されていますが、参照されたデータにアクセスする方法は指定されていません。したがって、仮想マシンごとに異なるアクセス方法があります。 主に 2 つの方法があります:
ハンドルを使用する: ハンドルには、ハンドルを格納するためのハンドル プールとして領域を確保します。オブジェクトのデータ型。参照に格納されるポインタは、オブジェクトのハンドルのアドレスです。参照はハンドルを通じて間接的にオブジェクトにアクセスします。利点は、オブジェクトが移動するときに、四角形内のポインターを変更するだけでよく、対応する参照を変更する必要がないことです。
直接アクセス: 参照にはオブジェクトのアドレスが保存され、データに直接アクセスできます。リファレンスを通じて。 Java ペアのデータ オブジェクトには、前述の型ポインターなど、オブジェクトのデータ型へのポインターが含まれています。この方法の利点は、アクセス速度が速く、ハンドルを使用する方法と比較してポインタの位置決めのオーバーヘッドが節約されることです。 HotSpotVM はこの方法を使用します。
2 つの使用方法の図は次のとおりです。 画像ソース http://www.th7.cn/Program/java/201604/846729.shtml
ガベージ コレクション アルゴリズム
オブジェクトがデッド、使用できなくなったアルゴリズムが 2 つあります:
参照カウント アルゴリズム: オブジェクトの場合、参照回数が 1 増えるとカウントが 1 増加し、参照が無効になるとカウントが減少します。カウントが 0 の場合、オブジェクトは死亡したと見なされます。このアルゴリズムは効率が高いという特徴がありますが、オブジェクト間の相互参照の問題を解決することが困難です。このアルゴリズムは、MS COM テクノロジーや Python などで使用されます。
到達可能性分析アルゴリズム: このアルゴリズムの核心は、GC ルートから開始して、参照されているすべてのオブジェクトを検出することです。オブジェクトと GC ルートの間に参照チェーンがない場合、そのオブジェクトは無効であると見なされます。このアルゴリズムを使用するには、Java、C#などが使用されます。
GC ルートとして使用できるオブジェクトは次のとおりです:
仮想マシン スタック (スタック フレーム内のローカル変数テーブル) で参照されるオブジェクト
メソッド領域のクラスの静的プロパティによって参照されるオブジェクト
メソッド領域の定数によって参照されるオブジェクトメソッド領域
ネイティブ メソッド
で参照されるオブジェクトには、Java で 4 つの参照強度があります:
強参照: 強参照はガベージ コレクターによってリサイクルされることはありません
ソフト参照: システムはそれを表す SoftReference クラスを提供します。まだ利用可能であるが、必要なオブジェクトではないことを示します。リサイクルのタイミングは、参照オブジェクトをリサイクルした後、メモリが足りない場合にはOOM
を行います。弱い参照: WeakReference クラスで表されるこのタイプの参照は、次のガベージ コレクションまでのみ存続します。ガベージ コレクターが動作すると、現在のメモリが十分であるかどうかに関係なく、弱参照のみに関連付けられたオブジェクトがリサイクルされます。つまり、GC が発生する限り、弱い参照は再利用する必要があります。 GC ルートに到達しなくなった参照チェーンとの違いは、これらのオブジェクトは引き続き弱い参照を通じてアクセスできますが、参照チェーンのないオブジェクトには二度とアクセスできないことです。
仮想参照: PhantomReference によって実装されます。オブジェクトの生存時間には影響しません。その存在の重要性は、仮想参照によって参照されるオブジェクトがリサイクルされるときにシステム通知を受け取ることです。
システムの GC ワークフローを次の図に示します。一般に、リサイクルされるオブジェクトはマーキング プロセスを 2 回実行し、リサイクルを回避するためにそれ自体を Finalize メソッドに保存することがあります。
いくつかの典型的なガベージ コレクション アルゴリズム:
HotSpot VM でのガベージ コレクション アルゴリズムの具体的な実装の詳細: 正確な結果を得るには、GC はスキャン時にすべてのスレッドをフリーズする必要があります。現在主流の Java 仮想化は正確な GC を採用しています。つまり、HotSpot を例に挙げると、システムはそのようなマッピング レコードを実装するために OopMap と呼ばれるデータ構造を使用します。このような情報により、仮想マシンはオブジェクト参照がどこに保存されているかを直接知ることができるため、メモリを 1 つずつチェックする必要がなくなり、GC スキャンが高速化されます。プログラムの命令ごとに参照関係やメモリデータが変更される場合があり、その場合、対応するOopMapデータを命令ごとに生成するとかなりの容量を消費することになります。セーフティ ポイントの概念 (SafePoint) は、各スレッドがそのスレッドに対応する安全なポイントまで実行される場合にのみ GC スキャンが実行されるため、安全なポイントにある命令に対してのみ OopMap を生成できるため、その数が削減されます。オープマップの。安全なポイントの選択では、GC の頻度とシステム パフォーマンスの総合的な影響を考慮する必要があります。一般に、メソッド呼び出し、ループ ジャンプ、例外ジャンプなどの「プログラムを長時間実行できる特性を持つ」ポイントは、安全なポイントを選択する必要があります。選択されました。スレッドを安全なポイントまで実行し、GC スキャンのために停止できるようにするには、プリエンプティブ割り込みとプロアクティブ割り込みの 2 つの方法があります。ここで別の問題が発生します。たとえば、スリープ状態のスレッドに遭遇した場合、安全なポイントでスリープしていない場合、安全なポイントには決して移動しないことになります。安全領域(SafeRegion)という概念も提案された。つまり、このエリアの点は安全な点である。スレッドがセーフ ポイントに入ると、スレッドはセーフ エリアに入ったことをマークし、セーフ エリアから出る前に GC が完了するまで待つ必要があります。
さまざまなガベージ コレクター:
最も一般的なメモリ割り当てルールのいくつか:
オブジェクトは最初に Eden 領域に割り当てられます: Eden 領域のメモリが不十分な場合、システムはより高速なマイナー GC を開始します
大きなオブジェクトは古い世代に直接入ります: 長い配列や文字列などの大きなオブジェクトの場合は、古い世代の領域に直接割り当てます。したがって、ライフサイクルが短い大きなオブジェクトは GC を引き起こす可能性が高いため、できるだけ避ける必要があります。
長期間存続するオブジェクトは古い世代に移行します: オブジェクトが Survivor 領域で複数回 (デフォルトでは 15 回) のマイナー GC に耐えた場合、そのオブジェクトは古い世代に移動されます。
動的なオブジェクトの年齢の決定: この記事は前の記事と結合されます。Survivor 内の同じ年齢のすべてのオブジェクトのサイズの合計が Survivor の半分を超える場合、その年齢がこれ以上のオブジェクトになります。 age は 15 回待たずに古い世代の領域に移動されます。
スペース割り当ての保証: 新しい世代のコピー収集アルゴリズム。パラメーターが許可されている場合、マイナー GC の実行後、すべての存続オブジェクトを Survivor に配置できない場合、多くのオブジェクトが古い世代領域に直接配置されます。古い世代に十分なスペースがない場合、より多くのスペースを取得するためにフル GC が発生します