Java 堆、堆栈和永久生成中的静态分配

最近,我阅读了很多关于 Java 内存分配方案的文章,当我从各种来源阅读这些文章时,我发现有很多疑问。我已经收集了我的概念,我要求通过所有的点和评论他们。我开始知道内存分配是特定于 JVM 的,所以我必须事先说明,我的问题是特定于 Sun 的。

  1. 类(由类加载器加载)进入堆上的一个特殊区域: 永久生成
  2. 所有与类相关的信息,比如类的名称、与类相关的对象数组、 JVM 使用的内部对象(比如 java/lang/Object)以及优化信息都进入了永久生成区域。
  3. All the static member variables are kept on the Permanent Generation area again.
  4. 对象放在不同的堆上: 年轻一代
  5. 每个类只有一个方法的副本,无论是静态方法还是非静态方法。那份复印件放在永久一代区域。 对于非静态的方法,所有的参数和局部变量都会进入堆栈——只要对该方法进行具体的调用,我们就会得到一个与之相关联的新堆栈框架。 I am not sure where are the local variables of a static method are stored. Are they on the heap of Permanent Generation ? Or just their reference is stored in the Permanent Generation area, and the actual copy is somewhere else (Where ?)
  6. I am also unsure where does the return type of a method get stored.
  7. 如果对象(在年轻一代中)需要使用静态成员(在永久一代中) ,它们被给予静态成员的引用 & & 它们被给予足够的内存空间来存储方法的返回类型,等等。

谢谢你经历了这一切!

69641 次浏览

首先,现在你应该很清楚,很少有人可以从第一手的知识来证实这些答案。很少有人研究过最近的 HotSpot JVM,或者对它们进行了深入研究,以便真正了解它们。这里的大多数人(包括我自己)都是根据他们在别处看到的东西或者他们推断的东西来回答的。通常写在这里,或在各种文章和网页,是基于其他来源,可能是或可能不是决定性的。它常常被简化、不准确或者完全错误。

如果您想要确认您的答案,您确实需要下载 OpenJDK 源代码... ... 和 做你自己的研究,通过阅读和理解源代码。提出关于 SO 的问题,或者浏览随机的网络文章,都不是一种合理的学术研究方法。

Having said that ...

我的问题只针对 Sun。

在人们提出这个问题时,昇阳电脑已不复存在。因此,这个问题是甲骨文特有的。在 AFAIK,所有当前(非研究)的第三方 JVM 实现要么是 OpenJDK 发行版的直接端口,要么是另一个 Sun/Oracle 发行版的后裔。

下面的答案适用于 Oracle Hotspot 和 OpenJDK 发行版,可能也适用于大多数其他发行版... ... 包括 GraalVM。

1) Classes (loaded by the classloaders) go in a special area on heap : Permanent Generation.

在 Java8之前,是的。

在 Java8中,PermGen 空间已经被 Metaspace 取代。已加载和 JIT 编译的类现在可以到那里。PermGen 已经不存在了。

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

差不多吧。我不知道你说的那些是什么意思。我猜测“ JVM 使用的内部对象(如 java/lang/Object)”指的是 JVM 内部类描述符。

3)所有静态成员变量再次保存在永久发电区域。

变量本身是的。这些变量(像所有 Java 变量一样)将保存原始值或对象引用。但是,虽然静态成员变量位于在永久堆中分配的帧中,但是这些变量引用的对象/数组可以在 任何堆中分配。

4)对象进入不同的堆: 年轻一代

不一定。大型对象 被直接分配到终身使用权生成中。

5)每个类只有一个方法的副本,无论是静态方法还是非静态方法。那份复印件放在永久一代区域。

Assuming that you are referring to the code of the method, then AFAIK yes. It may be a little more complicated though. For instance that code may exist in bytecode and/or native code forms at different times during the JVM's life.

对于非静态的方法,所有的参数和局部变量都会进入堆栈——只要对这个方法进行具体的调用,我们就会得到一个与之相关联的新的堆栈框架。

是的。

我不确定静态方法的局部变量存储在哪里。他们是永恒一代的人吗?或者只是它们的引用存储在永久生成区域,而实际的副本在其他地方(在哪里?)

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

6) I am also unsure where does the return type of a method get stored.

如果您指的是由(非 void)方法调用返回的 价值,那么它要么在堆栈上返回,要么在机器寄存器中返回。如果在堆栈上返回,则需要1个或2个单词,具体取决于返回类型。

7) If the objects (in the young generation) nees to use a static member (in the permanent generation), they are given a reference to the static member && they are given enough memory space to store the return type of the method,etc.

这是不准确的(或者至少,你没有清楚地表达自己)。

如果某个方法访问一个静态成员变量,那么它得到的是一个基本值或者一个对象 参考文献。这可以分配给(现有的)局部变量或参数,分配给(现有的)静态或非静态成员,分配给以前分配的数组的(现有的)元素,或者简单地使用和丢弃。

  • 在任何情况下,都不需要分配 新的存储来保存引用或基元值。

  • Typically, one word of memory is all that is needed to store an object or array reference, and a primitive value typically occupies one or two words, depending on the hardware architecture.

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


欲了解更多信息,请参考以下资源: