web-dev-qa-db-ja.com

Java-ヒープ、スタック、および永久生成の静的割り当て

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

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

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

110
Jaguar

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

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

そうは言っても ...

1)クラス(クラスローダーによってロードされる)は、ヒープ上の永続的な領域であるPermanent Generationに移動します。

わかった、はい。 (Update:以下を参照してください。)

2)クラスの名前、クラスに関連付けられたオブジェクト配列、JVMで使用される内部オブジェクト(Java/lang/Objectなど)、最適化情報など、クラスに関連するすべての情報が永続生成領域に入力されます。

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

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

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

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

必ずしも。ラージオブジェクトは、終身世代に直接割り当てることができます

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

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

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

はい。

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

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

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

valueが(voidではない)メソッド呼び出しによって返されることを意味する場合、スタックまたはマシンレジスタで返されます。スタックで返される場合、返されるタイプに応じて1語または2語を取ります。

7)オブジェクト(若い世代)が静的メンバー(永続世代)を使用する必要がある場合、オブジェクトには静的メンバーへの参照が与えられます。

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

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

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

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

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

[〜#〜] update [〜#〜]

Java 8の時点で、PermGenスペースはMetaspaceに置き換えられました。詳細については、次のリソースを参照してください。

142
Stephen C