ホームページ >Java >&#&チュートリアル >JAVA仮想マシン(JVM)の詳しい解説(2) - メモリ分割
C 言語では、オブジェクトを使用したい場合は、そのオブジェクトに対して新しい操作を実行する必要があり、そのオブジェクトを使用しなくなった場合は、そのオブジェクトに対して削除操作を実行する必要があることがわかっています。開発者が削除ステートメントの作成を忘れると、メモリ リークが発生します。 [メモリがオブジェクトによって占有されており、返されない場合、それはメモリ リークと呼ばれます。 】
しかし Java は賢く、「手動」から「自動」に進化し、メモリの制御を仮想マシンに引き渡しました。 jvm が自動メモリ管理をどのように実行するかを見てみましょう。
#自動メモリ管理は 2 つの部分に分かれています。:
オブジェクトへのメモリの割り当てと、オブジェクトに割り当てられたメモリの再利用です。この記事では、前者であるメモリのパーティショニングとメモリの割り当てについて説明します。次の記事では GC (ガベージ コレクション) について説明しましょう。1. メモリ分割
仮想マシンのメモリの内容を見てみましょう。 JVMのメモリ領域は、クラスファイル、クラスローディングサブシステム、ランタイムデータ領域、実行エンジンに大別されます。今日はランタイムデータ領域についてのみ説明します。 [この画像はJDK7をベースにしています。 JDK7以前では、定数プールはメソッド領域に格納されていました。 JDK7以降、定数プールはヒープ上に配置されるようになりました。 ]スレッド パブリック
ランタイム データ領域では、メソッド領域とヒープがスレッドにパブリックです。この 2 つのエリアは「リサイクル」されているため、ガベージ コレクションを行う必要があります。仮想マシンの起動時に作成されます。スレッド プライベート
仮想マシン スタック、ローカル メソッド スタック、およびプログラム カウンターはスレッドに対してプライベートです。これらはスレッドとともに「生きたり消えたり」し、" one-time" なので、ガベージ コレクションを行う必要はありません。 (1) メソッド領域
ランタイム定数プールがあります。格納されるのは、Class ファイルに記述されたシンボル参照、つまり直接参照です。新しい定数は、コンパイル時と実行時の両方でこのプールに入れることができます。
(2) ヒープ
概念: スタックがプログラムの動作の問題、つまりプログラムがデータをどのように処理するかの問題を解決する場合、ヒープは解決します。これはデータ ストレージの問題、つまりデータをどこにどのように置くかという問題です。 機能:a. ヒープは仮想マシン メモリの最大の部分であり、メモリの約 4 分の 3 を占めます。たとえば、32 ビット Windows プラットフォーム上の各プロセスに 2GB のメモリがある場合、通常は 1.5GB のメモリがヒープに割り当てられます。ヒープが多くのスペースを占有していることがわかります。b. 論理的に連続している限り、物理的に不連続なメモリ空間であってもかまいません。
メモリ割り当ての観点から見ると、複数のスレッドプライベート割り当てバッファを分割できます。
#(3) 仮想マシンスタック#仮想マシンスタックにはスタックフレームが格納され、スタックフレームにはローカル変数テーブルが格納されます。 、ダイナミックリンク、メソッド出口およびその他の情報。
#スタック内のスタック フレーム
各メソッドは実行中にスタック フレームとメソッドを作成します。呼び出しから実行完了までは、スタック フレームを仮想マシン スタックにプッシュしてからポップアウトするまでのプロセスに対応します。
スタック フレームのローカル変数テーブル
には、コンパイル時に既知のさまざまな基本データ型、オブジェクト参照、および returnAddress 型が格納されます。したがって、必要なメモリ空間はコンパイル中に割り当てることができ、そのサイズは実行時に変わりません。
基本データ型が占有する領域を割り当てる場合、2 つのローカル変数領域を占有する 64 ビット長および double 型のデータを除き、他のデータ型は 1 つだけを占有します。(4) ローカル メソッド スタック
ローカル メソッド スタックと仮想マシン スタックは、仮想マシン スタックが Java メソッドを実行することを除いて、同じ機能を持ちます。 、ネイティブ メソッド スタックはネイティブ メソッドを実行します。
Java メソッドは開発者によって記述された Java コードであり、ネイティブ メソッドは Java が非 Java コードを呼び出すためのインターフェイスです。
(5) プログラムカウンタ
プログラムカウンタには、現在のスレッドが実行するバイトコードの行番号が格納されます。 jvm が動作するときは、このカウンターの値を変更することによって、実行する必要がある次のバイトコード命令を選択します。
2. メモリ割り当て
#このパートでは、Java でオブジェクトがどのように割り当て、レイアウトされ、アクセスされるかについて説明します。ヒープとメモリ割り当ての原則。
オブジェクトの作成
new を使用してオブジェクトを作成します。システムの実行時に仮想マシンが何を行うかを見てみましょう。新しい 。現時点では、人間は肉のようなもので、人間の食卓に着くまでに何層ものセキュリティチェックを通過する必要があります。ステップ 1: 定数プールに対応するシンボル参照があるかどうかを確認します。 [メソッド領域に進む]
ステップ 2: このクラスがロード、解析、および初期化されているかどうかを確認します。 [メソッド領域に進む]
ステップ 3: 新しいオブジェクトのメモリを受け取ります。ポインター衝突とフリーリストの 2 つの方法があります。 [ヒープ内で続行]
ステップ 4: 割り当てられたメモリ空間をゼロ値に初期化します。
ステップ 5: オブジェクトがどのクラスのインスタンスであるか、オブジェクトのハッシュ コードなど、オブジェクトに必要な設定を行います。この情報は、オブジェクトのオブジェクト ヘッダーに保存されます。
ステップ 6: Java コードでオブジェクトに初期値が割り当てられている場合は、ステップ 6 が実行され、
#オブジェクトのメモリ レイアウト
メモリ内のオブジェクトのストレージ レイアウトは、次のように分割されます。 3 部: オブジェクト ヘッダー インスタンス データの配置と充填
オブジェクト ヘッダー
オブジェクト ヘッダーには 2 つの情報部分があります:(1)ハッシュ コード、GC 生成経過時間、ロック ステータス フラグなどを含む実行時データ。 (2) ポインター型。仮想マシンはこのポインターを使用して、このオブジェクトがどのクラスのインスタンスであるかを判断します。 インスタンス データインスタンス データには、コードで定義されたさまざまな種類のフィールドの内容が格納されます。 配置パディング配置パディングはプレースホルダーとして機能するため、必ずしも存在する必要はありません。オブジェクトのサイズが 8 バイトの整数倍であることを確認するだけで済みます。#オブジェクト アクセスの場所 オブジェクトを作成したら、そのオブジェクトを使用できるようになります。それを使用するとき、探しているオブジェクトをどのように見つけることができますか?ハンドルとダイレクト ポインタの 2 つの方法があります: ハンドル: ハンドル アクセスは、Java 内のメモリの一部を分割することです。ヒープ ハンドルにはハンドル プールとして、オブジェクト インスタンス データと型データの特定のアドレス情報が含まれます。 ダイレクトポインタ: ダイレクトポインタが「direct」である理由」というのは、ハンドルの中間を外すからです。したがって、ハンドルよりも速いです。 HotSpot 仮想マシンでは、この方法が使用されます。 #Java ヒープ内でオブジェクトがどのように割り当て、レイアウトされ、アクセスされるかについて説明した後、メモリ割り当ての原則について説明します。 メモリ割り当ての原則:
##ヒープは、新世代、旧世代、永続世代に大別されます。オブジェクトのメモリ割り当ては主に新世代の Eden 領域に割り当てられますが、場合によっては旧世代に直接割り当てられることもあります。割り当てルールは 100% 固定されているわけではなく、ガベージ コレクターの組み合わせとパラメーター設定によって異なります。参考として、いくつかの割り当て原則を以下に示します。 (1) オブジェクトは最初に Eden に割り当てられます。 (2) 大きな物体はそのまま老年期に入ります。 (3) 長期にわたって存続するオブジェクトは古い世代に入ります。 (4) 動的なオブジェクトの年齢の決定。 (5) スペース割り当ての保証。 上記は、JAVA 仮想マシンのメモリの分割です。その他の質問については、PHP 中国語 Web サイトを参照してください:
以上がJAVA仮想マシン(JVM)の詳しい解説(2) - メモリ分割の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。