垃圾回收——分代回收

分代垃圾回收

在《垃圾回收算法》中介绍了三种垃圾回收算法,但实际的JVM虚拟机它不会单独采用某一种算法,它结合前面的三种算法协同工作,具体的实现就是虚拟机中称之为分代的垃圾回收机制,它把我们的堆内存整个区域划分了两块,一个叫新生代,一个叫老年代。新生代又进一步划分为伊甸园、幸存区From和幸存区To。

为什么要做这样的一个区域划分?主要是因为在Java中有的对象是需要长时间使用,长时间使用的对象放在老年代中,而那些用完了就可以丢弃的对象就可以放在新生代中,这样的话就可以针对于对象生命周期的不同特点进行不同的垃圾回收策略。老年代的垃圾回收就很久才发生一次,新生代的垃圾回收就发生的比较频繁,新生代处理的都是朝生夕死的对象,老年代则是处理更有价值而且长时间存在的对象。这样针对于不同的区域采用不同的算法可以更有效的对垃圾回收进行管理。

当我们创建一个新的对象时,这个新对象默认就会采用伊甸园的一个空间,接下来可能会创建很多的对象并放入伊甸园中,伊甸园的空闲空间也就逐渐减少,当创建一个对象发现伊甸园的空间不够的时候,就会触发一次垃圾回收,这是在新生代的垃圾回收(Minor GC)。Minor GC触发以后,就会采用之前说的可达性分析算法,沿着GC Root引用链去找,看伊甸园的对象是有用的还是垃圾并进行标记。标记成功后就会采用复制算法,把存活的对象复制到幸存区To中,复制到幸存区TO之后,会让幸存对象的寿命加1,剩余在伊甸园的对象就可以进行全部的回收,然后再让幸存区From和幸存区To进行交换,至此第一次垃圾回收就完成了,此时伊甸园的空间又充足了,就可以继续向伊甸园分配对象。

当经过一段时间,伊甸园的空间又满了,这时触发第二次垃圾回收,这次的垃圾回收除了把伊甸园中幸存的对象找到之外,还需要在幸存区中找是否还有需要继续存活的对象。然后把伊甸园中存活的对象放到幸存区TO中并将寿命加1,除此之外还会把幸存区From中仍要存活的对象放在幸存区To中并在之前的寿命基础上加1。然后再来释放伊甸园和幸存区From的垃圾清理掉。然后交换From和To.这样伊甸园的空间又充足,第二次的垃圾回收就完成了。

幸存区中的对象不会永远在幸存区待着,当它的寿命超过了一个阈值,比如默认的阈值是15,即只要经历15次垃圾回收,对象还在存活,则说明这个对象价值比较高,经常在使用,这就没必要一直在幸存区中留着,因为以后垃圾回收还是不能回收这个对象,此时这个这个对象就会晋升到老年代中,因为老年代的垃圾回收频率比较低,不会轻易将它回收掉。这就是Minor GC垃圾回收的流程。

在不断的回收过程中,可能会出现老年代中的内存空间已经满了,新生代中的空间也满了,此时进行Minor GC就不能解决问题,此时就需要进行Full GC,一般这些垃圾回收都是在空间内存不足的时候才会触发。Full GC的含义就是老年代的空间不足时做一次整体的清理,从新生代到老年代,整个堆进行清理。

总结

  • 对象首先分配在伊甸园区域。
  • 新生代空间不足,触发Minor GC,伊甸园和From存活的对象使用Copy复制到TO中,存活的对象年龄加1并交换 from to
  • Minor GC 会引发Stop the world(在执行垃圾收集算法时,Java应用程序的其他所有线程都被挂起(除了垃圾收集帮助器之外)),之所以要暂停其他用户的线程,是因为在垃圾回收的过程中牵扯到对象的复制,即对象地址的改变,这种情况下,如果多个线程都在同时运行,就会造成一个混乱,对象都已经移动,其他线程再访问这个对象,根据原来的地址就找不到这个对象,所以才会引发STW。暂停其他用户线程,等垃圾回收成后,用户线程才能继续。
  • 当对象寿命超过阈值时会晋升至老年代,最大寿命是15次(4bit)。
  • 当老年代空间不足,会先尝试触发Minor GC,如果之后空间仍不足,会触发一次Full GC。FULL GC也会引起STW,只是老年代对应的STW时间更长。

猜你喜欢

转载自blog.csdn.net/qq_35363507/article/details/104930159