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有两个算法,一个是如何避免并发GCroot问题,一个是如何确定停顿时间
说实话这两个算法这么难,不知道要不要面试会不会考,先mark下来。
总的来说理解第一个文章就非常足够了,我觉得写的太好了。
总结
- 我们是基本上不可能实现收集器,也不可能改收集的算法,不需要去背太多那些收集器,可以说出个基本特点和原理即可,毕竟就算背下来人家深入问还是不会
- 所以学收集器就是学它的对象如何分配,GC过程的对象如何分配以帮助我们去调优堆的大小,这点上《深入理解jvm》这本书讲的少了一些
关于每个收集器的特点,我感觉可以背一下他们的优点,如何优化用户停顿时间的。这里留着到时候再整理,等刷了面经看看是否重要先

浙公网安备 33010602011771号