ホームページ >Java >&#&チュートリアル >JAVA仮想マシン関連知識 - JVMメモリモデルの詳細なグラフィックとテキストの説明
最近、私は非常に古典的な Java の本を読んでいました。「Java 仮想マシンの詳細 第 2 版」。数年前に読みましたが、当時は読むことに興味がありませんでした。とても混乱したので読むのをやめました。今読み返してみると、確かによく書かれており、理解できる知識も多く、とても勉強になりました。今後、本書の内容をもとに、Java 仮想マシンに関する知識をより深く学び、復習するための連載記事を執筆する予定です。
先週末の引越し後、自宅のブロードバンドが直りませんでした。この件を通信カスタマー サービスに N 回報告し、最終的に明日の朝にブロードバンドを移行するよう技術者に予約を入れました。これで、ブロードバンドなしの辛い日々は終わります。インターネットは一週間以上。この時期、いろいろ忙しくて一週間もブログを更新していなかったので、書くのをやめる前の状態や情熱がだんだんと薄れていくのはどうしてだろう。 !明日の週末を利用して、今週の学習コンテンツの一部を会社のコンピューターに記録してください。
JVM メモリ モデルは実際には非常に単純です:
1. 構成: Java ヒープ、Java スタック (つまり、仮想マシン スタック)、ローカル メソッド スタック、メソッド領域とプログラムカウンタ。
2. 共有するかどうか: メソッド領域とヒープ領域は、スレッドによって共有されます。仮想マシン スタック、ローカル メソッド スタック、およびプログラム カウンターは、スレッド分離とも呼ばれます。これら 2 つの知識ポイントは、JVM メモリ モデルを習得するための基礎となるため、覚えておく必要があります。
JVM のプログラム カウンタは小さなメモリ領域ですが、このメモリ領域は非常に興味深いものです。主な機能は 3 つあります:
1. ストレージの内容: 通常の Java メソッド (つまり、ネイティブ キーワードで変更されていないメソッド) の場合、実行中の現在の命令のアドレスが保存されますが、ネイティブ メソッドの場合、これは空です (未定義)、なぜですか?ローカル メソッドを呼び出すときに、JVM 仮想マシンのメモリ アドレスを超えた可能性があるためです。
2. スレッドプライベート: なぜプログラムカウンターはスレッドプライベートなのでしょうか?ストレージの内容に基づいて理解するのは簡単ですが、複数のスレッドが実行している場合、高速なスレッドもあれば、遅いスレッドも存在します。次に、遅いスレッドが実行から戻ってきて、そのアドレスが変更されていることが判明すると、混乱しませんか?
3. JVM 内でメモリ オーバーフロー (OutOfMemoryError) が報告されない唯一の領域です。
仮想マシンスタックには主にスタックフレームが格納され、ローカル変数テーブル、オペランドスタック、ダイナミックリンク、メソッド出口情報などが格納されます。ローカル変数テーブルには、メソッドで定義されたいくつかのローカル変数、オブジェクト参照、パラメータ、メソッドの戻りアドレスなどが格納されます。ローカル変数テーブルが占める領域のサイズは、メソッドの実行時にコンパイル時に決定できます。これは、ローカル変数テーブルに格納されている内容と組み合わせると容易に理解できます。変数テーブル。オペランド スタックは、現在の操作のデータのロードおよびアンロードとして理解できます。64 ビット長および double タイプの場合、各オペランドは 2 ワード幅 (スロット) を占有し、他のタイプのオペランドは 1 ワード幅 (スロット) を占有します。各メソッドの呼び出し時にスタックフレームが作成され、実行処理はスタックフレームが仮想マシンのスタックにプッシュされたり、スタックからポップアウトされたりする処理に相当します。スタック フレームの内容については、ネットユーザーが書いたブログ https://blog.csdn.net/xtayfjp... を参照してください。このブログは非常に優れており詳細です。一目でわかるように、スタック フレームの図を次に示します。
仮想マシンのスタック メモリ オーバーフローには 2 つの状況があります:
1. スレッドによって要求されたスタックの深さが、仮想マシンによって許可されている深さを超えているため、StackOverflowError がスローされます。コードを見ると、仮想マシンのスタックに問題がある可能性があると考えるべきです。
2. 仮想マシン スタックを動的に拡張できる場合 (最新の JVM は動的に拡張できますが、JVM では固定長の仮想マシン スタックも可能です)、拡張中に十分なメモリを適用できない場合、OutOfMemoryError 例外がスローされます。 。
この知識ポイントは、ネイティブ メソッドを呼び出すときに JVM にサービスを提供することと、JVM が使用する言語を除いて、比較的単純です。ローカル メソッド (Java など C 言語で実装された関数を呼び出すには、ネイティブ メソッドを定義して実装する必要があります)、使用方法やデータ構造は必須ではないため、さまざまな仮想マシンで自由に実装できます。さらに、HotSpot 仮想マシンは、ローカル メソッド スタックと仮想マシン スタックを 1 つに直接結合します。仮想マシン スタックと同様に、ローカル メソッド スタックも StackOverflowError と OutOfMemoryError をスローします。
メソッド領域は、Java 仮想マシンの仕様ではヒープ (ヒープ領域) に対応する論理的な部分として記述されています。ノンヒープ(非ヒープ地区)と呼ばれます。主に保存されるのは、静的変数、定数 (実行時定数を含む)、クラスロード情報、および Java コンパイル済みコードです。スペースのこの部分は、固定サイズまたは拡張可能である必要はありません。GC は静的変数、定数、およびクラス読み込み情報をリサイクルするため、通常はこれらのオブジェクトのリサイクル効果が不十分です。したがって、ガベージ コレクションを実装しないことも選択できます。この領域は永続世代とも呼ばれます。この領域のメモリが不足すると、OutOfMemoryError 例外も報告されます。
Java ヒープ領域は、すべてのオブジェクト インスタンスと配列オブジェクトがここに格納されるため、JVM メモリ内で最も大きな領域です。この領域はスレッドによって共有され、JVM の起動時に作成されます。考えてみてください。このような大きな領域がスレッド専用であれば、メモリが爆発的に増加するはずではありませんか。 Java 仮想マシンの仕様によれば、ヒープ領域の内容は論理的に連続していれば物理的に不連続であってもよく、実装時には固定サイズまたは拡張可能であり、通常は拡張可能です。 -Xms と -Xmx はヒープ サイズを調整するために使用されます。 Javaヒープ領域は、ライフサイクルの違いに応じて新世代と旧世代に分かれています。新しい世代は Eden 領域と Survivor 領域に細分化でき、Survivor は Survivor1 と Survivor2 に細分化できます。これら 2 つは通常、そのうちの 1 つだけを使用し、もう 1 つは GC 中に存続するオブジェクトを保持するために使用されます。ほとんどの新しいオブジェクトは Eden 領域に格納されます。大きな配列や List オブジェクトなどの大きなオブジェクトの場合は、JVM パラメータ -XX:PretenureSizeThreshold を使用して、指定されたサイズを超えるオブジェクトを古い世代に直接格納できます。プログラムを作成するときは、古い世代の GC コストが若い世代の GC コストよりも大きいため、存続して消滅する大きなオブジェクトが古い世代に入らないようにする必要があることに注意してください。 Eden と Survivor のデフォルトのサイズ比は 8:1:1 で、新しい世代のデフォルトの GC アルゴリズムはレプリケーション アルゴリズムです。古い世代のデフォルトの GC アルゴリズムはマーク照合です。これら 2 つの GC アルゴリズムについては、次のブログで説明します。
ヒープに十分なメモリがない場合、OutOfMemoryError 例外がスローされます。ヒープ領域のメモリ モデルについては、次の図を参照してください:
関連記事:
Java 仮想マシンの動作原理の詳細な説明(写真とテキスト)
関連動画:
Black Horse Cloud Classroom 8 日間で Python を徹底的に理解するビデオチュートリアル
以上がJAVA仮想マシン関連知識 - JVMメモリモデルの詳細なグラフィックとテキストの説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。