123

私は最近、Java のメモリ割り当てスキームについて多くのことを読んでいますが、さまざまな情報源から読んでいるため、多くの疑問がありました。私は自分の概念を集めました。すべてのポイントを調べて、それらについてコメントしたいと思います。メモリ割り当ては JVM 固有であることがわかったので、私の質問は Sun 固有であることを前もって言わなければなりません。

  1. クラス (クラスローダーによってロードされる) は、ヒープの特別な領域に移動します: 永久生成
  2. クラスの名前、クラスに関連付けられたオブジェクト配列、JVM によって使用される内部オブジェクト (java/lang/Object など)、および最適化情報など、クラスに関連するすべての情報は、Permanent Generation 領域に入ります。
  3. すべての静的メンバー変数は、Permanent Generation 領域に再び保持されます。
  4. オブジェクトは別のヒープに移動します: 若い世代
  5. メソッドが静的であるか非静的であるかにかかわらず、クラスごとに各メソッドのコピーは 1 つだけです。そのコピーは永久世代エリアに置かれます。非静的メソッドの場合、すべてのパラメーターとローカル変数がスタックに置かれ、そのメソッドの具体的な呼び出しがあるたびに、それに関連付けられた新しいスタック フレームが取得されます。静的メソッドのローカル変数がどこに格納されているかわかりません。彼らは永久世代の山にいますか?または、それらの参照だけが Permanent Generation 領域に格納され、実際のコピーは別の場所にあります (どこに?)
  6. メソッドの戻り値の型がどこに格納されるかもわかりません。
  7. オブジェクト (若い世代) が静的メンバー (永続世代) を使用する必要がある場合、静的メンバーへの参照が与えられます && メソッドの戻り値の型を格納するのに十分なメモリ空間が与えられます。

これを通過していただきありがとうございます!

4

1 に答える 1

161

まず、これらの答えを直接の知識から確認できる人はほとんどいないことは明らかです。最近の HotSpot JVM に取り組んだり、実際に知るために必要な深さまで研究したりした人はほとんどいません。ここにいるほとんどの人 (私自身を含む) は、他の場所で書かれているのを見たこと、または推測したことに基づいて回答しています。通常、ここ、またはさまざまな記事や Web ページに書かれていることは、決定的である場合とそうでない場合がある他の情報源に基づいています。多くの場合、単純化されているか、不正確であるか、単に間違っています。

回答の最終的な確認が必要な場合は、OpenJDK ソースコードをダウンロードする必要があります ...ソースコードを読んで理解することで、独自の調査を行う必要があります。SO について質問したり、ランダムな Web 記事を調べたりすることは、健全な学術研究手法ではありません。

そうは言っても ...

... 私の質問は Sun 固有のものです。

この質問がされた時点で、Sun Microsystems は存在していませんでした。したがって、質問はOracle固有のものでした。私の知る限り、現在の(研究ではない)サードパーティのJVM実装はすべて、OpenJDKリリースの直接ポートであるか、別のSun / Oracleリリースから派生しています。

以下の回答は、Oracle Hotspot および OpenJDK リリースに適用され、おそらく他のほとんどのリリースにも適用されます... GraalVM を含みます。

1) クラス (クラスローダーによってロードされる) は、ヒープ上の特別な領域に移動します: 永久生成。

Java 8 より前は、はい。

Java 8 の時点で、PermGen スペースは Metaspace に置き換えられました。ロードされ、JIT コンパイルされたクラスがそこに移動するようになりました。PermGen はもう存在しません。

2) クラスの名前、クラスに関連付けられたオブジェクト配列、JVM によって使用される内部オブジェクト (java/lang/Object など)、および最適化情報など、クラスに関連するすべての情報は、Permanent Generation 領域に入ります。

多かれ少なかれ、はい。それらのいくつかであなたが何を意味しているのかわかりません。「JVM で使用される内部オブジェクト (java/lang/Object など)」とは、JVM 内部のクラス記述子を意味すると推測しています。

3) すべての static メンバー変数は、Permanent Generation 領域に再び保持されます。

変数自体ははい。これらの変数 (すべての Java 変数と同様) は、プリミティブ値またはオブジェクト参照のいずれかを保持します。ただし、静的メンバー変数は permgen ヒープに割り当てられたフレーム内にありますが、これらの変数によって参照されるオブジェクト/配列は任意のヒープに割り当てられます。

4) オブジェクトは別のヒープに移動: 若い世代

必ずしも。大きなオブジェクト、Tenured 世代に直接割り当てることができます。

5) メソッドが静的であるか非静的であるかにかかわらず、クラスごとに各メソッドのコピーは 1 つだけです。そのコピーは永久世代エリアに置かれます。

メソッドのコードを参照していると仮定すると、私の知る限りそうです。ただし、もう少し複雑な場合があります。たとえば、そのコードは、JVM の存続期間中のさまざまな時点でバイトコードおよび/またはネイティブ コード形式で存在する可能性があります。

... 非静的メソッドの場合、すべてのパラメーターとローカル変数がスタックに格納されます。そのメソッドの具体的な呼び出しがあるたびに、それに関連付けられた新しいスタック フレームが取得されます。

はい。

... 静的メソッドのローカル変数がどこに格納されているかわかりません。彼らは永久世代の山にいますか?または、それらの参照のみが永久世代領域に保存され、実際のコピーは別の場所にあります (どこに?)

いいえ。非静的メソッドのローカル変数と同様に、スタックに格納されます。

6) メソッドの戻り値の型がどこに格納されるかもわかりません。

(非 void) メソッド呼び出しによって返される値を意味する場合、スタックまたはマシン レジスタに返されます。スタックに返される場合、戻り値の型に応じて 1 または 2 ワードかかります。

7) オブジェクト (若い世代) が静的メンバー (永久世代) を使用する必要がある場合、静的メンバーへの参照が与えられます && メソッドの戻り値の型を格納するのに十分なメモリ空間が与えられます。 .

それは不正確です (少なくとも、あなたは自分自身を明確に表現していません)。

一部のメソッドが静的メンバー変数にアクセスする場合、取得するのはプリミティブ値またはオブジェクト参照です。これは、(既存の) ローカル変数またはパラメーターに割り当てられたり、(既存の) 静的メンバーまたは非静的メンバーに割り当てられたり、以前に割り当てられた配列の (既存の) 要素に割り当てられたり、単に使用されて破棄されたりする可能性があります。

  • 参照またはプリミティブ値を保持するために新しいストレージを割り当てる必要はありません。

  • 通常、オブジェクトまたは配列参照を格納するために必要なのはメモリの 1 ワードだけであり、ハードウェア アーキテクチャに応じて、プリミティブ値は通常 1 ワードまたは 2 ワードを占有します。

  • メソッドによって返されたオブジェクト/配列を保持するために、呼び出し元がスペースを割り当てる必要はありません。Java では、オブジェクトと配列は常に値渡しセマンティクスを使用して返されますが、返される値はオブジェクトまたは配列参照です。


詳細については、次のリソースを参照してください。

于 2010-10-03T12:55:30.300 に答える