JVM学习(六)垃圾收集器

垃圾收集器的分类

为什么会分新生代和老年代回收器的区别?

因为新生代GC触发次数多,垃圾对象回收多,所以要把内存整齐度和效率优先。而老年代内存空间大,垃圾对象少。如果再使用复制算法,需要浪费很多空间。

整堆垃圾收集器

语言描述如下:

  • 串行(Serial)回收器是单线程的一个回收器,简单、易实现、效率高。
  • 并行(ParNew)回收器是Serial的多线程版,可以充分的利用CPU资源,减少回收的时间。
  • 吞吐量优先(Parallel Scavenge)回收器,侧重于吞吐量的控制。
  • 并发标记清除(CMS,Concurrent Mark Sweep)回收器是一种以获取最短回收停顿时间为目标的回收器,该回收器是基于“标记-清除”算法实现的

 

JVM推荐不修改默认的垃圾收集器,优先调整堆的大小来提高性能。也就是说理解下面这些收集器尤为重要

  • jdk1.7 默认垃圾收集器Parallel Scavenge(新生代)+Parallel Old(老年代)
  • jdk1.8 默认垃圾收集器Parallel Scavenge(新生代)+Parallel Old(老年代)
  • jdk1.9 默认垃圾收集器G1

垃圾收集器

要想理解垃圾收集器,从以下三个方面入手

  • 对象的分配策略
  • 对象的回收策略
  • 如何降低用户停顿时间

Parallel Scavenge+Parallel Old

内存空间

对象的分配

这里的对象大于等于Eden区一半,Serial收集器没有这个规则,这也是与《深入理解jvm》书上的不同地方。其他的都一样

存活的对象

GC触发的时机

第一次eden区满后

  • 1. 把所有非垃圾对象复制到Survivor1区,分代年龄+1
  • 2. 然后把eden区所有对象清理

第二次eden区满后

  • 1. 把eden区和Survivor1区存活对象复制到Survivor2区,分代年龄+1
  • 2. 把eden区和Survivor1区所有对象清理

第三次eden区满后

  • 1. 把eden区和Survivor2区存活对象赋值到Survivor1区,分代年龄+1
  • 2. 把eden区和Survivor2区所有对象清理

以此循环

  • 当分代年龄加到15就会放入老年代,永久不会清除,如静态变量,线程池的线程
  • 当老年代满了,会执行一次full gc 就是针对堆全部执行gc,如果仍然回收不了就是内存溢出OOM

注意点

  • 什么时候会进入老年代?

对象大于等于eden区一半,同年龄对象总和大于等于Survivor空间一半,所以对eden区和Survivor区的空间分配尤为重要。(因为如果不是老对象而是需要被回收的进入了old区会逐步导致fullgc,用户线程停顿很久)

 

代码验证(这里的代码验证是存在分析问题的,因为它没有分析新对象大于等于eden区一半就会进入老年区)

 

Garbage First

关于G1收集器的对象分配过程,这个文章讲的太好了

关于G1有两个算法,一个是如何避免并发GCroot问题,一个是如何确定停顿时间

答案可以参考这个

说实话这两个算法这么难,不知道要不要面试会不会考,先mark下来。

总的来说理解第一个文章就非常足够了,我觉得写的太好了。

总结

  • 我们是基本上不可能实现收集器,也不可能改收集的算法,不需要去背太多那些收集器,可以说出个基本特点和原理即可,毕竟就算背下来人家深入问还是不会
  • 所以学收集器就是学它的对象如何分配,GC过程的对象如何分配以帮助我们去调优堆的大小,这点上《深入理解jvm》这本书讲的少了一些

 

关于每个收集器的特点,我感觉可以背一下他们的优点,如何优化用户停顿时间的。这里留着到时候再整理,等刷了面经看看是否重要先

posted @ 2021-01-21 21:29  王者之剑KO  阅读(88)  评论(0)    收藏  举报