Java垃圾收集器实现了一种按年龄对对象进行分类的分代垃圾收集策略。
必须标记和压缩JVM中的所有对象是低效的。随着越来越多的对象被分配,对象列表会增加,导致垃圾收集时间变长。应用程序的经验分析表明,Java中的大多数对象都是短期的。这就是为什么Java将对象分类为几代,并相应地执行垃圾收集。
(资料图片)
年轻一代
新创建的对象始于年轻一代。年轻一代进一步细分为:
l 伊甸园空间—所有新对象都从这里开始,初始内存分配给它们
l 幸存者空间(FromSpace和ToSpace)—在经历了一个垃圾收集周期后,对象从伊甸园移到这里。
当对象被年轻一代垃圾收集时,这是一个小的垃圾收集事件。当伊甸园空间充满对象时,将执行次要GC。所有死亡对象都被删除,所有活着的对象都被移动到一个幸存者空间。次要GC还检查幸存者空间中的对象,并将它们移动到另一个幸存者空间。
以以下顺序为例:
1.伊甸园拥有所有对象(活的和死的)
2.小规模的垃圾收集—所有死亡对象都会从伊甸园中移除,所有活动对象都将移动到S1(FromSpace),伊甸园和S2现在是空的。
3.新对象被创建并添加到伊甸园,伊甸园和S1中的一些物体已经死亡。
4.小规模的垃圾收集—所有死亡对象都从伊甸园和S1中移除,所有活动对象都移动到S2(ToSpace),伊甸园和S1现在是空的。
因此,在任何时候,一个幸存者空间总是空的。当幸存物体达到一定的移动阈值时,它们会移动到老一代。你可以使用-Xmn标志来设置年轻一代的大小。
老一代
长寿物体最终会从年轻一代转移到老年一代,这也被称为“终身世代”,它包含了在幸存者空间中停留很长时间的对象。为对象的使用期限定义了一个阈值,该阈值决定了在将其移到旧一代之前,它可以存活多少个垃圾收集周期。
当对象从老一代被垃圾收集时,这是一个主要的垃圾收集事件。你可以使用-Xms和-Xmx标志来设置堆内存的初始大小和最大大小。
由于Java使用了分代垃圾收集,对象存活的垃圾收集事件越多,它在堆中的提升就越大。它从年轻一代开始,如果存活时间足够长,最终会在终身制一代结束。
请考虑以下示例,以了解对象在空间和代之间的升级:
当一个对象被创造时,它首先被放入年轻一代的伊甸园空间。一旦发生一次小的垃圾收集,来自伊甸园的活动对象将被提升到FromSpace。当下一次小垃圾收集发生时,来自伊甸园和FromSpace的活动对象将移动到ToSpace,此循环持续特定次数,如果对象在这一点之后仍在使用,下一个垃圾收集周期将把它移到老一代空间。
永久代
类和方法等元数据存储在永久代中。JVM在运行时根据应用程序使用的类填充它,不再使用的类可能会被永久生成垃圾收集。你可以使用-XX:PermGen和-XX:MaxPermGens标志来设置永久代的初始大小和最大大小。
元空间
从Java 8开始,元空间内存空间取代了PermGen空间。实现与PermGen不同,堆的这个空间现在自动调整大小,这避免了由于堆的PermGen空间有限而导致应用程序内存不足的问题。元空间内存可以被垃圾收集,当元空间达到最大大小时,不再使用的类可以被自动清理。