Javaでの静的割り当て-ヒープ、スタック、永続的な生成


117

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

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

ご覧いただきありがとうございます!

回答:


152

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

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

そうは言っても ...

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

この質問がなされたとき、Sun Microsystemsは存在しなくなりました。したがって、問題はOracle固有のものでした。私の知る限り、すべての現在の(調査ではない)サードパーティのJVM実装は、OpenJDKリリースの直接ポートであるか、別のSun / Oracleリリースの子孫です。

以下の回答は、Oracle HotspotとOpenJDKのリリース、およびおそらくGraalVMを含む他のほとんどのリリースにも当てはまります。

1)クラス(クラスローダーによってロードされる)は、ヒープ上の特別な領域、Permanent Generationに入ります。

Java 8より前は、そうです。

Java 8以降、PermGenスペースはメタスペースに置き換えられました。ロードされ、JITコンパイルされたクラスがそこに移動します。PermGenは存在しません。

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

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

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

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

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

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

5)クラスごとに各メソッドのコピーが1つだけあります。メソッドは静的でも非静的でもかまいません。そのコピーは、Permanent Generation領域に配置されます。

メソッドのコードを参照していると仮定すると、AFAIKはそうです。少し複雑かもしれませんが。たとえば、そのコードは、JVMの存続期間のさまざまな時点でバイトコードやネイティブコードの形式で存在する可能性があります。

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

はい。

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

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

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

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

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

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

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

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

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

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


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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.