logo头像

小时候,哭是我们解决问题的绝招。长大后,笑是我们面对现实的武器。

深入理解JVM - 垃圾回收之世代垃圾收集过程

前言

深入理解 - 垃圾回收 中我们详细讲解了JVM垃圾回收的机制、垃圾收集算法以及各种垃圾回收器的原理和优缺点。

通过上一篇文章我们知道现在主流的垃圾回收器都采用了分代收集算法,本文我们就来详细讲解下垃圾回收器是如何进行分代收集垃圾的

JVM分代

分代其实就是将堆分成几个部分,分别是新生代、老年代和永久代

新对象会被分配在新生代内存。一旦新生代内存满了,就会开始对死掉的对象,进行所谓的小型垃圾回收过程。一旦新生代内存里,死掉的越多,回收过程就越快;至于那些还活着的对象,此时就会老化,并最终老到进入老年代内存。

Stop the World 事件 —— 小型垃圾回收属于一种叫 “Stop the World” 的事件。在这种事件发生时,所有的程序线程都要暂停,直到事件完成(比如这里就是完成了所有回收工作)为止。

老年代用来保存长时间存活的对象。通常设置一个阈值,当达到该年龄时,年轻代对象会被移动到老年代。最终老年代也会被回收。这个事件称为Major GC

Major GC 也会触发STW(Stop the World)。通常,Major GC会慢很多,因为它涉及到所有存活对象。所以,对于响应性的应用程序,应该尽量避免Major GC。还要注意,Major GC的STW的时长受年老代垃圾回收器类型的影响。

永久代 包含JVM用于描述应用程序中类和方法的元数据。永久代是由JVM在运行时根据应用程序使用的类来填充的。此外,Java SE类库和方法也存储在这里。

如果JVM发现某些类不再需要,并且其他类可能需要空间,则这些类可能会被回收。

世代垃圾回收过程

现在我们已经理解了为什么堆被分成不同的代,接下来我们一起来看看这些空间是如何相互作用,JVM中的对象是如何分配和老化的

  1. 首先,将任何新对象分配给Eden空间,两个survivor空间都是空的

  2. 当eden空间填满时,会触发轻微的垃圾收集

  3. 引用的对象被移动到第一个survivor空间,清除eden空间时,将删除未引用的对象

  4. 在下一次的Minor GC中,Eden区也会做同样的操作。删除未被引用的对象,并将被引用的对象移动到Survivor区。然后,他们被移动到了第二个Survivor区(S1)。此外,第一个Suvivor区(S0)中,在上一次Minor GC幸存的对象,会增加年龄,并被移动到S1中。待所有幸存对象都被移动到S1后,S0和Eden区会被清空。注意,Survivor区中有了不同年龄的对象。

  5. 在下一次的Minor GC中,会重复同样的动作。不过,这一次Survivor区会交换。被引用的对象移动到S0,幸存的对象增加年龄。Eden区和S1被清空

  6. 在较小的GC之后,当老化的物体达到一定的年龄阈值(在该示例中为8)时,它们从年轻一代晋升到老一代。

随着较小的GC持续发生,物体将继续被推广到老一代空间。

所以这几乎涵盖了年轻一代的整个过程。 最终,将主要对老一代进行GC,清理并最终压缩该空间。