在Java中的静态分配 – 堆,堆栈和永久生成

我最近在java中对内存分配scheme进行了大量的研究,而且我从各种来源阅读的时候都有很多疑问。 我已经收集了我的概念,并且要求通读所有的观点并对其进行评论。 我知道内存分配是特定于JVM的,所以我必须事先说,我的问题是Sun特有的。

  1. 类(由类加载器加载)进入堆中的特殊区域:永久生成
  2. 所有与类名相关的信息,与类关联的对象数组,与JVM使用的内部对象(如java / lang / Object)以及优化信息相关的信息都会进入永久生成区域。
  3. 所有静态成员variables都保留在永久变形区域。
  4. 对象走在另一堆:年轻一代
  5. 每个类的每个方法只有一个副本,方法是静态的或非静态的。 该副本放在永久代区域。 对于非静态方法,所有的参数和局部variables都进入堆栈 – 每当有一个具体的方法调用时,我们就得到一个新的与之关联的栈帧。 我不知道静态方法的局部variables存储在哪里。 他们在永久一代吗? 或者只是他们的参考文献被存储在永久代的区域,而实际的副本是在别的地方(哪里?)
  6. 我也不确定方法的返回types存储在哪里。
  7. 如果对象(在年轻一代)需要使用静态成员(在永久代),它们被赋予一个静态成员的引用&&它们被给予足够的内存空间来存储方法的返回types等。

感谢您通过这个!

首先,现在应该清楚的是,很less有人能够从第一手知识中确认这些答案。 很less有人在最近的HotSpot JVM上工作,或者研究他们到真正需要的深度。 这里的大多数人(包括我在内)都是根据他们在别处看到的东西或者他们推断出的东西来回答的。 通常在这里或在各种文章和网页上写的是基于其他来源,可能或可能不确定。 通常它是简化的,不准确的或者明显的错误。

如果你想确定你的答案,你真的需要下载OpenJDK源代码…并通过阅读和理解源代码做你自己的研究 。 对SO提出问题,或者通过随机的networking文章进行拖网不是一个很好的学术研究技术。

话说回来 …

1)类(由类加载器加载)进入堆中的特殊区域:永久代。

AFAIK,是的。 ( 更新 :见下文)

2)与类名相关的所有信息,与类关联的对象数组,与JVM使用的内部对象(如java / lang / Object)以及优化信息相关的所有信息进入永久生成区域。

或多或less,是的。 我不确定你说的这些东西是什么意思。 我猜测“JVM使用的内部对象(如java / lang / Object)”意味着JVM内部的类描述符。

3)所有的静态成员variables都保存在永久生成区域。

variables本身是的。 这些variables(如所有Javavariables)将保存原始值或对象引用。 但是,虽然静态成员variables位于在permgen堆中分配的框架中,但这些variables引用的对象/数组可能会分配到任何堆中。

4)对象走在另一堆:年轻一代

不必要。 大型对象可以直接分配到终身代。

5)每个类每个方法只有一个副本,方法是静态的或非静态的。 该副本放在永久代区域。

假设你指的是方法的代码,那么AFAIK是的。 虽然这可能会稍微复杂一些。 例如,在JVM的使用期限内,代码可能以字节码和/或本地代码forms存在。

…对于非静态方法,所有的参数和局部variables进入堆栈 – 每当有一个具体的方法调用,我们得到一个新的相关的堆栈帧。

是。

…我不知道静态方法的局部variables存储在哪里。 他们是在永久变种的堆? 或者只是他们的参考文献被存储在永久代的区域,而实际的副本是在别的地方(哪里?)

不,它们存储在堆栈中,就像非静态方法中的局部variables一样。

6)我也不确定方法的返回types存储在哪里。

如果你的意思是一个(非void)方法调用返回的 ,那么它将被返回到堆栈或者一个机器寄存器中。 如果它在堆栈中返回,则根据返回types,这需要1或2个字。

7)如果对象(在年轻一代)需要使用一个静态成员(在永久代),他们被给予一个静态成员的引用&&他们有足够的内存空间来存储方法的返回types等。

这是不准确的(或者至less,你没有清楚expression自己)。

如果某个方法访问一个静态成员variables,它得到的是一个原始值或一个对象引用 。 这可以被分配给分配给(现有的)静态或非静态成员,分配给先前分配的数组的(现有的)元素的(现有的)局部variables或参数,或者简单地被使用和丢弃。

  • 在任何情况下都不需要分配新的存储空间来保存参考值或原始值。

  • 通常,存储器的一个字是存储对象或数组引用所需的全部内容,而原始值通常占据一个或两个字,具体取决于硬件体系结构。

  • 在任何情况下,调用者都不需要分配空间来容纳方法返回的某个对象/数组。 在Java中,对象和数组总是使用按值传递的语义来返回…但返回的值是对象或数组引用。

UPDATE

从Java 8开始,PermGen空间已经被Metaspace所取代。 有关更多信息,请参阅以下资源:

  • PermGen和Metaspace有什么不同?
  • Java 8:从PermGen到Metaspace
  • 关于G1垃圾收集器,永久代和Metaspace