Java 堆术语:年轻代、老年代和永久代?

358

我正在尝试理解Java堆术语中的年轻代老年代永久代的概念,特别是它们之间的相互作用。

我的问题如下:

  • 什么是年轻代?
  • 什么是老年代?
  • 什么是永久代?
  • 这三个代之间如何相互作用/关联?

假设您正在谈论Sun JDK/OpenJDK,请参阅OpenJDK网站上的存储管理页面。底部有几个链接可提供更多信息。 - Nicholas Riley
1
与这个问题“终身一代”相关的编程内容 - gstackoverflow
如果你还在寻找,这是一个很棒的视频,讲解了GC中的老一代和年轻一代:https://youtu.be/OnodHoNYE1Y - Benedikt
5个回答

333

这似乎是一个常见的误解。在Oracle的JVM中,永久代不是堆的一部分。它是一个单独的空间,用于存储类定义和相关数据。在Java 6及更早版本中,字符串池也存储在永久代中。在Java 7中,字符串池存储在主对象堆中。

这篇关于永久代的文章很好。

我喜欢Oracle的JConsole指南中给出的每个空间的描述:

对于HotSpot Java VM,使用串行垃圾回收的内存池如下:

  • 伊甸园空间(堆):为大多数对象最初分配内存的池。
  • 幸存者空间(堆):包含已经从伊甸园空间垃圾回收过来的对象。
  • 老年代(堆):包含已经在幸存者空间中存在一段时间的对象。
  • 永久代(非堆):包含虚拟机本身的所有反射数据,例如类和方法对象。对于使用类数据共享的Java VM,此代被分为只读区域和可读写区域。
  • 代码缓存(非堆):HotSpot Java VM还包括一个代码缓存,其中包含用于编译和存储本机代码的内存。

Java使用分代垃圾回收。这意味着如果您有一个名为foo的对象(它是某个类的实例),它经过更多的垃圾回收事件(如果仍然有对它的引用),就会被推广得越多。它从年轻代开始(年轻代本身又分为多个空间-伊甸园和幸存者),最终可能在老年代中存活。


3
我相信从Java 7开始,字符串不再在永久代中被池化。 - Tim Goodman
14
“老”和“终身职位”是同义词吗?“新”和“幸存者”是同义词吗? - joadha
2
永久代仅适用于Java 8之前的版本。 - Jackie
@Joshua McKinnon您好,我有一个问题,就是变量的不同内存空间(Eden、Survivor和Tenured space)有什么用途? - Vikas Verma
2
如果您仍在等待答案,是的,@joadha 您是正确的。请查看此链接:https://codeahoy.com/2017/08/06/basics-of-java-garbage-collection/ - recepinanc
显示剩余5条评论

241

堆(Hep)可分为年轻代和老年代,具体如下:

年轻代:这是对象生命周期短暂的地方,又分为两个空间:

  • 伊甸园(Adam and Eve first lived) 空间:使用new关键字创建对象时,会在此空间上分配内存。
  • 幸存者区(Survivor Space):这是一个池,包含了从伊甸园空间经过Java垃圾回收后存活下来的对象。

老年代: 这个池主要包含永久代和虚拟(保留)空间,将存放在年轻代垃圾回收后仍存活的对象。

  • 永久代(Tenured Space):这个内存池包含了在多次垃圾回收后仍存活的对象,即从幸存者区垃圾回收后仍存活的对象。

永久代: 内存池中包含永久类元数据和描述符信息,因此永久代空间总是为类和与之相关的内容预留,例如静态成员。

Java8更新:永久代已被元空间(Metaspace)所代替,非常相似。
主要区别在于Metaspace可以在运行时动态调整大小。
Java Metaspace空间:无界(默认)

代码缓存(Code Cache): (虚拟或保留) : 如果使用HotSpot Java VM,则包括包含内存的代码缓存区,在其中进行编译和本地代码存储。

enter image description here

来源


@Premraj,Metaspace可以在运行时动态调整大小,即可以在运行时扩展。这意味着默认情况下它没有上限的唯一区别是什么? - gstackoverflow
1
很好,请问方法区、本地栈和运行时常量池在这张图片中位于哪里?它们分别保存什么内容? - user6091735
如果用于本地方法代码的代码缓存,那么本地方法堆栈(每个线程将有一个)会有什么? - user6091735

64

什么是年轻代?

年轻代用于分配和回收新的对象。当年轻代被填满时,会触发一次小型垃圾收集。年轻代中死亡的对象会很快被回收。一些存活的对象会被移动到老年代。

什么是老年代?

老年代用于存储生命周期较长的对象。通常设置一个阈值来判断对象是否应该从年轻代移动到老年代。最终老年代也需要进行垃圾回收,这个事件被称为大型垃圾回收

什么是永久代?

永久代包含JVM运行所需的元数据信息,描述应用程序中使用的类和方法。永久代在运行时根据应用程序使用的类进行填充。

自Java 8发布以来,PermGen已被Metaspace取代。

现在将忽略PermSize和MaxPermSize参数。

这三代如何相互交互/关联?

enter image description here

图片来源和Oracle Technetwork教程文章: http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html

以上文章中的"垃圾回收过程概述"通过多个图示详细解释了三代之间的交互关系。

请参考下面的总结图:

这里输入图片描述

该段内容是一个HTML代码块,其中包含了一个超链接和图像标签。需要注意的是,需要保留原有的HTML标签以确保页面正常渲染。

非常好。请问这张图片中方法区、本地栈和运行时常量池分别位于哪里?它们分别保存了什么内容? - user6091735
请参考 https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-2.html 了解更多细节。方法区在虚拟机启动时创建。尽管方法区在逻辑上是堆的一部分,但简单的实现可能选择不对其进行垃圾回收或压缩。每个运行时常量池都分配在Java虚拟机的方法区中。 - Ravindra babu
你确定吗?我一直在阅读它是PermGen空间的一部分(不是堆)?http://www.journaldev.com/2856/java-jvm-memory-model-memory-management-in-java - user6091735
Oracle文档更加权威。 - Ravindra babu
年轻代对象的阈值是按时间单位(例如毫秒)还是GC轮次设置的? - Very Objective

17
Java虚拟机被组织为三个代:年轻代、老年代和永久代。大多数对象最初分配在年轻代。老年代包含已经经历了一定数量的年轻代垃圾回收的对象,以及一些可能直接分配到老年代的大对象。永久代保存JVM认为方便由垃圾回收器管理的对象,例如描述类和方法的对象,以及类和方法本身。

3
SunHotSpot JVM中的内存分为三代:年轻代、老年代和永久代。
- 年轻代:新创建的对象被分配到年轻代。 - 老年代:如果新对象请求更大的堆空间,则直接分配到老年代。也有一些经过几次GC周期后仍然存活的对象会晋升到老年代,即长生命周期的对象驻留在老年代。 - 永久代:永久代保存JVM认为方便垃圾回收器管理的对象,例如描述类和方法的对象,以及类和方法本身。
需要注意的是,永久代不被视为Java堆的一部分。
这三代之间的交互/关系如何呢?除了大对象外,对象首先被分配到年轻代。如果一个对象在x个垃圾回收周期后仍然存活,则会晋升到老年代。因此,我们可以说年轻代包含短生命周期的对象,而老年代包含长生命周期的对象。永久代与其他两代没有交互。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接