JVMはインタビューの質問をする必要があります-メモリ管理の質問
Jvm Must Ask Interview Questions Memory Management Questions
インタビュアー:JVMメモリのパーティション分割?
回答:
-
メソッド領域(スレッド共有):クラス情報、定数、静的変数、仮想マシンによってコンパイルされたコンパイラのコンパイル済みコードなどのデータを格納するために、各スレッドによって共有される領域。 Java仮想マシン仕様では、メソッド領域がヒープの論理部分として記述されていますが、非ヒープと呼ばれるエイリアスがあり、Javaヒープとは区別する必要があります。
-
ランタイム定数プール:コンパイラーによって生成されたさまざまなリテラルおよびシンボル参照を保持するメソッド領域の一部。
-
-
ヒープメモリ(スレッド共有):すべてのスレッドで共有される領域で、ガベージコレクターによって管理されるメイン領域です。現在、主なガベージコレクションアルゴリズムは世代別コレクションアルゴリズムであるため、Javaヒープは、新世代と旧時代のより精巧なEdenスペース、From Survivorスペース、To Survivorスペースなど、デフォルトでは新しい学生に細分化できます。 8:1:1の比率で分配されます。 Java仮想マシン仕様によると、Javaヒープは、ディスクのように論理的に連続している限り、物理的に隣接していないメモリ空間に置くことができます。
-
プログラムカウンタ:Javaスレッドは、オペレーティングシステムのPCカウンタと同様にプライベートであり、現在のスレッドによって実行されるバイトコードの行番号インジケータと考えることができます。スレッドがJavaメソッドを実行している場合、このカウンターは、ネイティブメソッドが実行されている場合に実行されている仮想マシンのバイトコード命令のアドレスを記録し、カウンター値は空(未定義)です。このメモリ領域は、Java仮想マシン仕様でOutOfMemoryError条件を指定しない唯一の領域です。
-
仮想マシンスタック(スタックメモリ):Javaスレッドプライベート、仮想マシン展示では、Javaメソッドによって実行されるメモリモデルについて説明します。各メソッドは、ローカル変数、オペランド、動的リンク、メソッドエクスポート、および各メソッド呼び出しが意味するその他の情報を格納するためのスタックフレームを作成します。スタックフレームが仮想マシンスタックのスタックにプッシュされます
-
ローカルメソッドスタック:Java仮想マシンスタックと同様に、違いは、エリアがネイティブメソッドを使用してJVMにサービスを提供することです。
インタビュアー:オブジェクト割り当てルール?
回答:
-
オブジェクトは、エデンエリアに優先的に割り当てられます。 Eden領域に十分なスペースがない場合、仮想マシンはマイナーGCを実行します。
-
大きなオブジェクトはすぐに古い時代になります(大きなオブジェクトは、多くの連続したメモリスペースを必要とするオブジェクトです)。目標は、Edenエリアと2つのSurvivorエリアの間で大量のメモリがコピーされるのを回避することです(新世代はレプリケーションアルゴリズムを使用してメモリを収集します)。
-
長期的に生き残った物は老後を迎えました。仮想マシンは、各オブジェクトの経過時間カウンターを定義します。オブジェクトがマイナーGCを1回通過すると、オブジェクトはサバイバーエリアに入ります。各マイナーGCの後、オブジェクトの年齢は1ずつ増加します。しきい値オブジェクトが古い年齢に達することが知られています。
-
オブジェクトの年齢を動的に決定します。サバイバーエリア内の同じ年齢のすべてのオブジェクトの合計がサバイバースペースの半分より大きい場合、その年齢以上のオブジェクトは直接古い年齢に入ることができます。
-
スペース割り当ての保証。マイナーGCが実行されるたびに、JVMはサバイバーエリアのエージングエリアに移動されたオブジェクトの平均サイズを計算します。この値が古い領域の残りの値より大きい場合、フルGCが実行されます。 HandlePromotionFailure設定よりも小さい場合、trueの場合、モニターのみが実行されます。 GC、falseの場合は、フルGCを実行します。
インタビュアー:Javaのメモリモデル
回答:
Java仮想マシン仕様は、Javaメモリモデル(JMM)を定義して、ハードウェアとオペレーティングシステムのレイヤー間のメモリアクセスの違いをマスクし、Javaプラットフォーム間で一貫したメモリアクセスを実現しようとします。効果。
Javaメモリモデルは、すべての変数がメインメモリに格納されることを指定します。各スレッドには、独自の作業メモリーもあります。スレッドの作業メモリーには、スレッドが使用する変数のメインメモリーコピーのコピーが格納されます。スレッドのすべての操作(読み取り、割り当てなど)はスレッド内にある必要があります。これはメインメモリで実行され、メインメモリで変数を直接読み書きすることはできません。異なるスレッドは、相手の作業メモリー内の変数に直接アクセスすることはできません。スレッド間の変数値の転送は、メインメモリによって完了する必要があります。スレッド、メインメモリ、ワーキングメモリの関係は上記のとおりです。
インタビュアー:2つのスレッド間でどのように通信しますか?
A:で 共有メモリ 同時実行モデルでは、スレッドはプログラムの共通状態を共有し、スレッドはメモリ内の共通状態を読み書きすることによって暗黙的に通信します。典型的な共有メモリ通信方法は、共有オブジェクトを介して通信することです。
たとえば、スレッドAとスレッドBの間で通信する場合は、次の2つの手順を実行する必要があります。
-
1.最初に、スレッドAはローカルメモリAを共有変数に更新し、それをメインメモリにフラッシュします。
-
2.次に、スレッドBはメインメモリに移動して、スレッドAの前に更新された共有変数を読み取ります。
に メッセージング 同時実行モデルでは、スレッド間にパブリック状態はなく、スレッドは明示的にメッセージを送信して明示的に通信する必要があります。 Javaの一般的なメッセージパッシングメソッドは、wait()とnotify()です。
インタビュアー:メモリバリア?
分析:これが並べ替えの問題をある程度理解する前に、ここで共有する良い記事を見つけました:Javaメモリアクセスの並べ替えの研究
A:メモリバリアは、メモリバリアとも呼ばれ、メモリ操作の順次制限を実装するために使用される一連のプロセッサ命令です。
インタビュアー:なぜメモリバリアが重要なのですか?
A:メインメモリへのアクセスには、通常、ハードウェアの数百クロックサイクルが必要です。プロセッサは、キャッシュによってメモリ遅延のコストを桁違いに削減できます。これらのキャッシュは、パフォーマンスのために保留中のメモリ操作の順序を並べ替えます。つまり、プログラムの読み取りおよび書き込み操作は、必ずしもプロセッサを必要とする順序で実行されるとは限りません。これらの最適化は、データが不変である場合や、データがスレッドのスコープに制限されている場合は無害です。これらの最適化を対称型マルチプロセッシングおよび共有可変状態と組み合わせるのは悪夢です。共有された可変状態に基づくメモリ操作が並べ替えられると、プログラムは無期限に動作する可能性があります。あるスレッドによって書き込まれたデータは、データが書き込まれる順序に一貫性がないため、他のスレッドに表示される場合があります。メモリバリアを適切に配置すると、プロセッサに保留中のメモリ操作を順番に実行させることで、この問題を回避できます。
インタビュアー:-Xms、-Xmnパラメーターの意味と同様
回答:
ヒープメモリの割り当て:
-
JVMによって割り当てられるメモリは、-Xmsで指定されます。デフォルトは物理メモリの1/64です。
-
JVMに割り当てられる最大メモリは、-Xmxで指定されます。デフォルトは物理メモリの1/4です。
-
デフォルトの空きヒープメモリが40%未満の場合、JVMはヒープを最大制限の-Xmxまで増やし、空きヒープメモリが70%を超えると、JVMは最小制限の-Xmsまでヒープを減らします。
-
したがって、サーバーは通常、各GCの後にヒープのサイズを変更しないように、-Xms、-Xmxを等しく設定します。オブジェクトのヒープメモリは、ガベージコレクタと呼ばれる自動メモリ管理システムによって再利用されます。
非ヒープメモリ割り当て:
-
JVMは、-XX:PermSizeを使用して、非ヒープメモリの初期値を設定します。デフォルトは物理メモリの1/64です。
-
ヒープ以外の最大メモリサイズは、XX:MaxPermSizeによって設定されます。デフォルトは物理メモリの1/4です。
-
-Xmn2G:若い世代のサイズを2Gに設定します。
-
-XX:SurvivorRatio、若い世代のサバイバーエリアに対するエデンエリアの比率を設定します。
インタビュアー:メモリリークとメモリリーク
回答:
概念:
-
メモリオーバーフローは、メモリが不足していることを意味します。
-
メモリリークは、オブジェクトが到達可能であることを意味しますが、それは役に立ちません。つまり、GCによってリサイクルされるべきだったオブジェクトはリサイクルされていません。
-
メモリリークは、メモリリークの原因の1つです。メモリリークは、メモリリークを引き起こす可能性があります。
メモリリークの原因の分析:
-
長いライフサイクルオブジェクトとは、短いライフサイクルオブジェクトを指します
-
役に立たないオブジェクトをnullに設定しませんでした
インタビュアー:Javaでオブジェクトを作成するプロセスの簡単な説明は?
分析:この質問に答えるには、まずクラスのライフサイクルを理解する必要があります。
回答:
Javaでのオブジェクトの作成は、ヒープにメモリスペースを割り当てるプロセスです。ここでのオブジェクトの作成は、配列オブジェクトの作成を含まない、newキーワードによって作成された通常のJavaオブジェクトに限定されます。
一般的なプロセスは次のとおりです。
1.クラスがロードされているかどうかを確認します。
仮想マシンがnewで実行されると、最初に定数プールに移動して、このクラスのシンボリック参照を見つけます。シンボル参照が見つかった場合、このクラスはメソッド領域にロードされ(メソッド領域には仮想マシンがロードしたクラスに関する情報が格納されます)、シンボル参照が見つからない場合はクラスローダーで実行を続行できます。クラスのロードを実行するために使用されます。クラスがロードされた後、プロセスは続行されます。
2.オブジェクトにメモリを割り当てます。
クラスがロードされた後、仮想マシンはオブジェクトへのメモリの割り当てを開始し、この時点で必要なメモリの量が決定されます。ヒープに必要なメモリを割り当てるだけです。
特定のメモリ割り当てには2つのケースがあります。1つはメモリスペースが完全に規則的である場合、もう1つはメモリスペースが連続していない場合です。
-
絶対メモリ正規化の場合、仮想マシンは、占有メモリと使用可能スペースの間でポインタを移動するだけで済みます。この方法は、ポインタの衝突と呼ばれます。
-
メモリの不規則性の場合、仮想マシンは、使用可能なメモリを記録するためのリストを維持する必要があります。メモリを割り当てるときは、空きメモリスペースを見つけて、割り当てられたリストに記録する必要があります。これにより、空きリストになります。
メモリを割り当てるときは、スレッドセーフの問題も考慮する必要があります。 2つの解決策があります:
-
1つ目は、CASを使用して操作のアトミック性を確保する、同期アプローチを使用することです。
-
もう1つは、各スレッドが独自のスペースにメモリを割り当てることです。つまり、各スレッドは、ローカルスレッド割り当てバッファ(TLAB)と呼ばれるヒープ内の小さなメモリを事前に割り当て、TLABにメモリを割り当てます。配布、互いに干渉しないでください。
3.割り当てられたメモリスペースのゼロ値を初期化します:
オブジェクトのメモリ割り当てが完了したら、オブジェクトのメモリ空間をゼロの値に初期化する必要があります。これにより、初期値が割り当てられていなくても、オブジェクトを直接使用できます。
4.オブジェクトに追加の設定を行います。
メモリスペースを割り当ててゼロ値を初期化した後、仮想マシンはオブジェクトに必要なその他の設定を行う必要があります。設定は、オブジェクトが属するクラス、クラスのメタデータ情報、オブジェクトのハッシュコード、GCスコアなどのオブジェクトヘッダーにあります。世代年齢およびその他の情報。
5.initメソッドを実行します。
上記の手順を実行した後、オブジェクトは仮想マシンで正常に作成されますが、Javaプログラムの場合、オブジェクトは現時点ではゼロ値でのみ初期化されるため、作成を完了するにはinitメソッドを実行する必要があります。プログラムのコードに従って初期値を割り当てるには、initメソッドを呼び出した後、オブジェクトを使用できます。
これまでのところ、オブジェクトが生成されています。これは、新しいキーワードを使用してオブジェクトを作成するプロセスです。
インタビュアー:オブジェクトのメモリレイアウトは何ですか?
A:オブジェクトのメモリレイアウトは、オブジェクトヘッダー、インスタンスデータ、および配置パディングの3つの部分で構成されています。
-
オブジェクトヘッダー:オブジェクトヘッダーは、2つの情報部分で構成されています。最初の部分は、ハッシュコード、GC生成期間、ロックステータスフラグ、スレッドによって保持されているロックなど、ストレージオブジェクト自体のランタイムデータです。 2番目の部分は、クラスメタデータへのポインターである型ポインターです。
-
インスタンスデータ:データです
-
パディングを揃える:必ずしも存在する必要はなく、揃えるだけです
インタビュアー:オブジェクトはどのように見つけられ、アクセスされますか?
A:オブジェクトアクセスには、ハンドルの位置決めと直接ポインタの2種類があります。
-
ハンドルの配置:Javaヒープは、メモリの一部をハンドルプールとして描画し、参照はオブジェクトのハンドルアドレスを格納し、ハンドルにはオブジェクトインスタンスデータとタイプデータの特定のアドレス情報が含まれます。
-
直接ポインタアクセス:Javaヒープオブジェクトは中央に配置されません。アクセスタイプデータに関する情報を配置する方法を検討する必要があり、参照にはオブジェクトアドレスが直接格納されます。
比較:直接ポインターの使用は高速で、ハンドル参照を使用して安定したハンドルを指し、オブジェクトはハンドル内のインスタンスデータへのポインターのみを変更するように移動され、参照自体を変更する必要はありません。