JVMメモリー領域
- プログラム・カウンタ: 現在のスレッドが実行したバイトコード・ファイルの行番号を記録します。
- スタック:ローカル変数テーブル、操作スタック、メソッド終了など ローカル変数には、基本型データ、オブジェクト参照など、メソッド呼び出しから実行終了までが格納され、仮想マシンのスタックフレームに対応してエントリから終了までが格納されます。
- ネイティブメソッドスタック:VMが使用するネイティブメソッドを提供します。
- ヒープ:オブジェクト・インスタンスや配列などを保持する、JVMが管理する最大のメモリー。
- メソッド領域: クラス情報、静的変数、定数、コンパイル済みコードを格納します。
OutOfMemoryError
プログラム・カウンターを除くすべての領域でOutOfMemoryError例外が発生する可能性があります。
- スタック:スレッドが仮想マシンで許容される深さ以上のスタック深さを要求すると StackOverflow 例外がスローされ、スタックの拡張時に十分なメモリを要求できないと OutOfMemoryError 例外がスローされます。
- ヒープ:ヒープ・メモリがインスタンスの割り当てを完了できず、拡張できない場合、OutOfMemoryError例外がスローされます。
解決方法は?スタックオーバーフロー:Xssでスタック容量を設定 ヒープオーバーフロー:メモリ解析ツールでメモリリークかメモリオーバーフローかを判断 メモリリーク:リークしたコードの場所を特定 メモリオーバーフロー:VMのヒープパラメータをチェックし、同時にコードをチェック。XmsとXmxでヒープ最小、最大を設定。
メモリ・リーク:割り当てられたメモリが再利用されず、メモリ領域の制御が失われることによるリソースの浪費を意味します。Javaでは通常、ゴミ・コレクターが自動的にゴミを再利用するため、メモリ・リークは発生しません。メモリ・リークが発生するのは、オブジェクトが作成され、そのオブジェクトへの参照が保存された後、そのオブジェクトが使用されず、ごみコレクターがそのオブジェクトを再利用しない場合です。メモリ・オーバーフロー(Memory Overflow):プログラムが必要とするメモリが、システムによって割り当てられるメモリの上限を超えること。
ゴミの収集
JVMメモリー領域のヒープとメソッド領域はスレッド共有で、プログラム・カウンター、スタック、ローカル・メソッド・スタックはスレッド非依存です。
- スレッド非依存領域:スレッドと一緒に生まれ、スレッドが終了するとメモリも一緒に回収されるため、ゴミ回収について深く考える必要がありません。
- スレッド共有領域:クラスとメソッドは異なるメモリを必要とし、どのオブジェクトを作成する必要があるかはランタイムのみが知っています。
ゴミ収集には3つの役割があります:
- 取り戻すべき記憶とは?
- 再利用するタイミング
- 再利用方法
再生が必要なメモリとは?オブジェクトが生きているかどうかを見分ける方法は?
- 参照カウント:循環参照問題があります
- ルート検索アルゴリズム:GCのルーツにオブジェクトが到達不可能である任意の参照を持っていない場合、最初のマーキングとスクリーニングが実行されます、このオブジェクトは、別のマーキングとスクリーニングに続いて、finalizeメソッドを実行する必要がある場合は、オブジェクトがリサイクルされますエスケープされません。
- GC 2011 Root として使用できるオブジェクトには、以下のものがあります:
- 仮想マシン・スタックで参照されるオブジェクト
- メソッド領域のクラス変数によって参照されるオブジェクト
- メソッド領域の定数によって参照されるオブジェクト
- ローカル・メソッド・スタックで参照されるオブジェクト
Javaメソッド内の 4 つの参照は
- 強い参照:オブジェクトが強い参照を持っている場合、オブジェクトはリサイクルされません。オブジェクト obj = new Object()
- ソフトリファレンス:メモリオーバーが発生する場合、再生成スコープに含まれる、有用だが本質的でないオブジェクトを記述するために使用されます。SoftReference softReference = new SoftReference(student);
- ダミー参照はいつでもリサイクルできます。 ダミー参照を配置する目的は、ダミー参照に関連付けられたオブジェクトが、ごみコレクタによってリサイクルされたときにシステム通知を受け取ることができるようにすることです。PhantomReference phantomReference = new PhantomReference(object, queue);
いつリサイクルするか?
- アプリケーションがアイドル状態のとき
- Javaヒープ・メモリが少ない場合
どのように再利用するのですか?
ゴミ収集アルゴリズム
- マーク・クリア・アルゴリズム:再生するオブジェクトをマークし、マークされたオブジェクトをクリア。欠点:低効率、メモリの断片化。
- コピー・アルゴリズム:メモリを2つのチャンクに分割し、一度に使用するのは1つのチャンクのみ。1つのチャンクを使い切ったら、生き残ったオブジェクトをもう1つのチャンクにコピーし、使用済みのメモリ・チャンクをすべてクリアします。デメリット:メモリが半分になります。
- マークソートアルゴリズム:リサイクルするオブジェクトにマークを付け、生き残ったオブジェクトをすべて一端へ移動させ、一端から先のオブジェクトを取り除きます。
- 世代別収集アルゴリズム:若い世代、オブジェクトは生きては死に、ゴミ収集のたびに生き残るオブジェクトは少なく、複製アルゴリズムに適しています。古い世代、オブジェクトの生存率は高く、マーク・アンド・クリーン/マーク・アンド・ソート・アルゴリズムに適しています。
ごみコレクター
レプリケーション・アルゴリズムを備えた新世代のコレクターは、ワールドを停止してすべてのユーザースレッドを一時停止する必要があります。
- シリアル・コレクター:シリアル・コレクター
- パーニューコレクター:パラレルコレクター
- 並列スカベンジャー・コレクター:スループット重視の並列コレクター
オールドエイジ・コレクター
- シリアル・オールド・コレクター:マーキング照合アルゴリズム、シリアル・コレクター、STOP THE WORLDの必要性。
- 並列古いコレクター:マーキング照合アルゴリズム、並列コレクター、世界を停止する必要があります。
- CMS コレクター:マーク除去アルゴリズム、ゴミ収集スレッドとユーザースレッドは同時実行可能、運用プロセス:
- 初期タグ付け:GCルートに直接接続されたオブジェクトにタグを付け、世界を停止します。
- 同時タグ付け:GC ルートに到達可能なオブジェクトにタグ付け。
- 再マーク:同時マーク中に変更されたオブジェクトをマーク、ワールドを停止。
- 同時クリア:マークされた領域をクリアします:
- CPU リソースに非常に敏感、デフォルトのゴミ収集スレッド数は /4。
- 浮遊ゴミ、同時パージ処理で発生したゴミは処理できません。
- マーカー除去アルゴリズム、多くのスペースデブリを生成
- G1 コレクター、プロセス:
- 初期マーキング:GC ルートに直接接続されたオブジェクトをマークし、世界を停止します。
- 同時タグ付け:GC ルートから到達可能なオブジェクトにタグ付け。
- 最終マーキング:同時マーキング中に変更されたオブジェクトをマークし、ワールドを停止します。
- フィルタリサイクル:タグ付けされた領域をクリアし、ユーザスレッドと同時に実行することができますが、ゴミの収集時間はユーザーによって制御することができるので、それはまた、世界を停止します。
- 利点
- 分割世代のリサイクル、新しい世代と古い世代を管理することができます。
- メモリ空間の断片化なし、全体として見ればマークソーティングアルゴリズム、局所的に見ればコピーアルゴリズム。
- 予測可能な停止時間:Javaヒープをリージョンに分割し、リージョンにどれだけゴミが溜まっているかを記録し、ゴミの回収時間から、毎回ゴミの多いリージョンを優先する優先リストを保持。
MinorGCと MajorGC
- MinorGC:新世代のゴミ収集、非常に頻繁。eden領域が十分な領域を確保できない場合、MinorGCを開始。
- MinorGCが発生したら、まず旧世代の最大利用可能連続空間が新世代の全オブジェクトの合計空間より大きいかどうかをチェックします。より小さい場合は、旧世代の最大利用可能連続空間が旧世代への各昇格の平均サイズより大きいかどうかをチェックし続け、より大きい場合はマイナーGCを試み、より大きい場合はメジャーGCを実行します。
- MajorGC:古いゴミ収集、MajorGCはMinorGCを伴いますが、MinorGCより10倍以上遅い。
新世代と旧世代
- 新世代:eden+survivor0+survivor1
- 老年期:長い文字列や長い配列のような大きなオブジェクトは老年期に直接割り当てられ、長期的に生き残ったオブジェクトは老年期に入ります。(老年期に昇格)。
一般的な JVM 構成パラメータ
- Xms最小ヒープ・サイズ
- Xmx最大ヒープ・サイズ
- スレッドあたりのXssスタックサイズ
- Xmn若い世代のサイズ
- XX:サバイバーエデンエリアとサバイバーエリアの比率を8に設定すると、2つのサバイバーエリアと1つのエデンエリアの比率は2:8となり、1つのサバイバーエリアが若い世代全体の1/10を占めます。
- XX:PretenureSizeThresholdオブジェクトは、老年期に直接割り当てられる大きさ以上のものです。
クラスのロード処理
- Load : クラスのバイナリ・バイト・ストリームをその完全修飾名でロードします。
- 検証:クラスファイルのバイトストリームに含まれる情報がjvmの要件を満たしているかどうかをチェックし、jvmのセキュリティを確保します。
- 準備:クラス変数へのメモリ確保と初期値の設定
- 説明: 定数プール内のシンボリック参照を直接参照に置き換えます。
- 例えば、CONSTANT_Class_info は、クラス・ファイル内のクラスやインターフェイスを表すために使用されます。
- 直接参照:定数を対応するクラス、メソッド、フィールドなどに解決します。
- 初期化:クラス変数、静的コードブロックなどの初期化。
クラス・ローダ
クラス・ローダーのソース・コード
- 指定された名前のクラスが既にロードされているかどうかをチェックし、ロードされている場合は再度ロードする必要はありません。
- 親ローダがある場合は、親ローダによってロードされます。親ローダがない場合は、スタートアップ・クラス・ローダを呼び出してロードします。
- 指定されたクラスが見つからない場合は、現在のクラス・ローダの findClass メソッドが呼び出され、クラスのロードが完了します。デフォルトの findClass は ClassNotFound 例外をスローするので、カスタム・クラス・ローダはこのメソッドをオーバーライドします。推測できますが、ApplicationClassLoaderのfindClassはクラスパスに移動してロードし、ExtentionClassLoaderはjava_home/lib/extディレクトリに移動してロードします。
2つの親の委譲モデル
クラスローダがクラスのロード要求を受け取ると、まず親クラスローダにロード要求を委譲します。すべてのクラスロード要求はトップレベルのスタータクラスローダに配送されるべきで、親ローダがロードできない場合にのみ子ローダがロードを試みます。
カスタム・クラス・ローダー
もし2つの親を持つデリゲーション・モデルを壊したくないのであれば、findClassメソッドだけを書き換えればよいでしょう。もし2つの親を持つデリゲーション・モデルを壊したいのであれば、loadClassメソッド全体を書き換えればよいでしょう。
親任期モデルの破壊
2つの親を持つデリゲーション・モデルは必須の制約ではなく、loadClassメソッド全体を書き換えることで破ることができます。




