JVMの基本(2つ):ランタイムデータ領域

序文

はじめまして〜私の記事を読んでようこそ。

前回の記事では、JVMの基本(1):仮想マシンについて、仮想マシンとは何か、およびバイトコードクラスファイルを紹介しました。この記事では、主にJVMのランタイムデータ領域構造について説明します。

c / c ++はメモリ内でスタックとヒープ領域に分割され、スタック領域は関数のローカル変数などを格納し、ヒープ領域はユーザーが開くスペースであることがわかっています。開発者が新しいオブジェクトを作成する必要がある場合、最初にヒープ領域にスペースを開き、次にそれを初期化して使用する必要があります。最後に、自分でメモリ領域を手動で解放する必要があります。JVMはこのすべての作業を完了しました。新しいオブジェクトを作成する必要があるnew場合は、オブジェクトを作成するためのキーワードのみが必要です。オブジェクトを使用しなくなった場合、ガベージコレクションメカニズムはメモリを自動的に再利用するのに役立ちます。どちらの方法にも独自の利点があります。C/ C ++にはメモリに対する最高の権利があり、オブジェクトのライフサイクルを管理する責任が重いことも意味します。JVMはメモリを自動的に管理し、開発者を直接のメモリ操作から保護します。 JVMのランタイムデータ領域について十分に知らないと、メモリリークやメモリオーバーフローなどの問題が発生しやすくなります。これは、JVMランタイムデータ領域を学習する必要がある理由の1つでもあります。

JVMランタイムデータ領域の構造はc / c ++に似ており、スタック領域とヒープ領域も割り当てられます。具体的な構造は次のとおりです。

クラスファイルは、クラスロードシステムを介して仮想マシンにロードされ、仮想マシンで処理されます。実行エンジンは、プログラムの実行、メソッドの呼び出し、およびそれらの実行を担当します。学部ライブラリのインターフェースとローカルメソッドライブラリは、Androidでの写真の撮影や通知など、プラットフォームに関連する一連のメソッドです。私たちの焦点は、ランタイムデータ領域にあります。メソッド領域とヒープはプロセスによって共有され、仮想マシンスタック、ローカルメソッドスタック、およびプログラムカウンターはスレッドによって共有されます。以下に各メモリ領域について説明します。

ヒープ領域

ヒープ領域は主にオブジェクトインスタンスを格納し、ガベージコレクションの主な目的です。ヒープ領域は物理的に連続していない場合がありますが、論理的に連続している必要があります。ヒープ領域はスレッドによって共有されます。

ヒープ領域は、注意が必要な重要なポイントです。作成するすべてのオブジェクトと配列(実際、配列も一種のオブジェクトです)は、ヒープ領域に割り当てられます。ヒープ領域はスレッドによって共有され、すべてのスレッドによって作成されたオブジェクトはヒープ領域に格納されます。ヒープ領域はガベージコレクションの主な目標であり、メモリリークや異常なメモリオーバーフローの発生率も高くなります。ヒープ領域はメモリのブロック全体ではありませんが、ガベージコレクション、スレッドセーフ、およびその他の問題を解決するために、世代別設計、スレッドバッファなどのさまざまな機能を実現するために分割されます。これについては、次の一連の記事。

ヒープ領域のサイズは、拡張可能または固定可能です。現在の主流の仮想マシンはすべて、拡張可能になるように設計されています。ヒープがメモリの適用に失敗し、拡張できない場合、OutOfMemoryErrorがスローされます。

メソッドエリア

メソッド領域には、主に、インスタントコンパイル後のクラス情報、定数、静的変数、およびコードキャッシュが格納されます。メソッド領域はスレッドによって共有されます。

クラスファイル内のクラスは、メソッド領域にロードおよび保存されます。定数、つまりfinal、コンパイル段階で値を決定できる型の変数、および静的変数はすべてこの場所に配置されます。バイトコードがインタープリターによって解釈された後のマシンコードも、この領域にキャッシュされます。

メソッド領域に格納されたデータのライフサイクルはプロセス全体に付随しているように見えますが、実際にはガベージコレクションも必要ですが、クラスのアンロードが非常に厳しいなど、リサイクルの効果を満足させることは困難です。タイミングについて。HotSpotの初期には、メソッド領域とヒープ領域が直接結合され、メソッド領域は不滅の世代と見なされ、ヒープは若い世代と古い世代に分けられました。メソッド領域とヒープ領域は直接でした。統一された方法でガベージコレクションが行われるため、特別な必要がなくなります。メソッド領域にガベージコレクションアルゴリズムのセットを記述します。この設計は、メモリオーバーフローの問題を簡単に引き起こす可能性があります。jdk8の後、HotSpotは不滅の生成を放棄し、ローカルメモリによって実現されるメタスペースに切り替えました。

新しいメモリ割り当て要件を満たすことができない場合、OutMemoryErrorがスローされます。

ランタイム定数プール

定数プールはメソッド領域の一部であり、主にデータ定数とシンボル参照を格納します。

一般に、ストレージ定数については疑いの余地はありませんが、final変更された定数です。シンボル参照には、パッケージ名、クラスの完全修飾名、メソッド名記述子などが含まれます。JVMは、コンパイル段階でコードのレイアウトを決定しないという点でc / c ++とは異なりますが、特定のクラスをロードして使用する必要があります。つまり、動的ロードです。次に、プログラム全体のすべてのクラスのシンボリック参照が定数プールに格納されます。クラスをロードする必要がある場合、クラスのシンボリック参照をクラスのロードのために定数プールから取得する必要があります。見つからない場合は、 ClassNotFoundErrorがスローされます。異常です。

定数プールは、データを作成するためのコンパイルフェーズにあるだけでなく、Stringインターンメソッドなどのランタイムフェーズで定数プールにデータを追加することもできます。したがって、定数プールがメモリを拡張できない場合、OutOfMemoryError例外がスローされます。

プログラムカウンター

プログラムカウンタは、現在のスレッドによって実行されたバイトコードの行番号のインジケータであり、プログラムの次のコード実行位置を示します。プログラムカウンタはスレッド専用です。

インタプリタは、プログラムカウンタを介してコードの実行を指示します。分岐、ループ、例外、ジャンプ、スレッドリカバリなどはすべて、制御するためにプログラムカウンタを必要とします。Javaのマルチスレッド実装は、プロセッサの実行時間を割り当てるためのスレッドローテーションです。スレッドが一時停止されると、プログラムカウンタは現在のスレッドコードの実行位置を記録し、スレッドが再開したときに正しいコード実行位置を復元できます。

通常の状況では、プログラムカウンタはバイトコード命令のアドレスを示します。ローカルメソッドが現在実行されている場合、プログラムカウンタの値は0です。このメモリはOOM例外をスローしません。結局のところ、1つのアドレスに格納され、多くのメモリ拡張を必要としません。

仮想マシンスタックとローカルメソッドスタック

仮想マシンスタックは、JVMメソッド実行のスレッドメモリモデルです。各メソッドが実行されると、スタックフレームが仮想マシンスタックにプッシュされます(ローカル変数、オペランドスタック、動的リンク、メソッド出口、オブジェクト参照を格納するために使用されます。その他の情報)。

ローカルメソッドスタック:仮想マシンスタックに似ていますが、実行されるメソッドのタイプはローカルメソッドです。

仮想マシンスタックは、c / c ++スタックにいくぶん似ています。JVMの各メソッドは、実行時にスタックフレームをプッシュし、メソッドの終了時にスタックフレームをポップします。スタックフレームにはメソッドにさまざまなデータ型が含まれていますが、スタックフレームはオブジェクト自体ではなくオブジェクト参照を保存し、特定のオブジェクトはヒープに格納されることに注意してください。スタックフレームに保存されるデータの最小単位は可変スロットです。可変スロットは、32ビット、64ビットなどのさまざまな仮想機会に応じて異なります。32ビットの可変スロットが使用されている場合、1つのintデータが1つの可変スロットを占有し、1つのdoubleデータが2つの可変スロットを占有します。

ネイティブメソッドスタックJava仮想マシンの仕様では、実装メソッドが明確に指定されていません。HotSpotは、ローカルメソッドスタックと仮想マシンスタックを1つに直接組み合わせて、統合管理を行います。

メソッドスタックは、StackOverFlowErrorとOutOfMemoryErrorの2つの例外をスローすることに注意してください。前者はスタックの深さが限界に達したときにスローされ、後者はスタックサイズを拡張するためにそれ以上のスペースを適用できない場合にスローされます。

総括する

この記事では、JVMの全体的なメモリ構造について説明し、実行時にデータ領域のさまざまな領域の機能と特性を分析します。

ランタイムデータ領域を理解することは、JVMのメモリ領域の分割を理解し、メモリリークとメモリオーバーフローが発生する場所を知ることです。これにより、より堅牢なコードを記述できます。同時に、ヒープ領域のGCメカニズムやオブジェクト作成プロセス、クラスローディングサブシステム、スレッドメモリモデルなど、JVMの他の知識を理解し続けるための基礎にもなります。すべてJVMモデル全体に​​基づいています。

これまでのところ、全文をオリジナルにするのは簡単ではありません。役立つ場合は、いいね、ブックマーク、コメント、転送、フォローできます。
著者は才能があり知識が豊富です。コメントエリアにコメントしてください。
転載が必要な場合は、プライベートメッセージをお願いします。

私の個人ブログへようこそ:ポータル

おすすめ

転載: blog.csdn.net/weixin_43766753/article/details/109208187