• 1

  • 513

  • 收藏

开工,来一杯JVM

1星期前

前言

年前更新了两篇JVM相关文章,过年虽然留深了但是一直没有写,今天开工继续水一篇,上一篇文章介绍了一下垃圾回收的基本入门知识,那么这一篇我们继续来了解垃圾回收的相关内容。

  • 了解一下分代回收?
  • 对象怎么样才会进入老年代?
  • 你知道哪些垃圾回收器?
  • 重点了解CMS和G1

1、了解一下分代回收

现在的垃圾回收器,都会在物理上或者逻辑上,把这两类对象进行区分。我们把死的快的对象所占的区域,叫作年轻代(Young generation)。把其他活的长的对象所占的区域,叫作老年代(Old generation)。在年轻代中选用复制算法,老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须使用“标记清理”或者“标记整理”算法。

  • 年轻代

年轻代使用的垃圾回收算法是复制算法——年轻代在发生GC之后,只有很小的对象会存活下来,复制这部分对象是非常高效的。

年轻代由Eden区和两个Survivor区组成,其中Eden区占80%的内存,每个Survivor区占10的内存,这个比例,是由参数 -XX:SurvivorRatio 进行配置的(默认为 8)。

对象在年轻代中每躲过一次GC,被转移到一块survivor区域中,年龄就会增长一岁,经过15次之后,就会转移到老年代中去。

  • TLAB( Thread Local Allocation Buffer)

JVM默认会给每个线程开辟一个buffer区域,用来加速对象的分配,这个buff就放在Eden区域中。类似于Java中的ThreadLocal,避免了对公共区域的操作以及一些锁竞争。

对象分配时会优先在TLAB上分配,但是TLAB通常都很小,所以对象比较大的时候,会直接在Eden区的共享区域进行分配。

  • 老年代

老年代一般使用标记清除、标记整理算法,原因是老年代的存活率一般都是比较高的,空间也比较大,拷贝起来比较不划算,所以采取就地收集的方式。

2、对象怎么样才会进入老年代?

  • 年龄到了

对象在年轻代中每躲过一次GC,被转移到一块survivor区域中,年龄就会增长一岁,经过15次之后,就会转移到老年代中去。

  • 空间分配担保

在年轻代中,每次存活的对象都会放入到一块survivor区域中,这个区域的默认比例是10%,但是我们没办法保证每次存活的对象都小于10%,所以当survivor空间不够时候,就需要依赖老年代进行分配担保,这时间对象会直接在老年代进行分配。

  • 大对象

超出某个大小的对象将直接在老年代分配。这个值是通过参数 -XX:PretenureSizeThreshold 进行配置的。默认为 0,意思是全部首选 Eden 区进行分配。

  • 动态年龄判断

有的垃圾回收算法,并不要求 age 必须达到 15 才能晋升到老年代,它会使用一些动态的计算方法。比如,如果幸存区中相同年龄对象大小的和,大于幸存区的一半,大于或等于 age 的对象将会直接进入老年代。

3、你知道哪些垃圾回收器?

年轻代垃圾回收器

Serial 垃圾收集器

单线程、STW、简单高效

这个回收器是一个单线程的回收器,它的“单线程”不仅仅是它只使用一个CPU或者一条收集线程去完成垃圾回收的工作,而且在它进行垃圾回收时,必须暂停其他所有的工作线程,直到回收结束。

虚拟机在Client模式下的默认新生代收集器,它优于其他收集器的地方:与其他收集器的单线程相比简单而高效,对于限定单个CPU的环境来说,Serial由于没有线程交互的开销,专注于垃圾收集可以获得最高的单线程收集效率。

ParNew 垃圾收集器

Serial 的多线程版本、可让垃圾线程和用户线程同时工作、可与CMS配合工作

Parallel Scavenge 垃圾收集器

使用复制算法、并行多线程回收器、吞吐量优先

老年代垃圾回收器

Serial Old 垃圾收集器

Serial Old是Serial的老年代版本,单线程、使用标记整理算法

两大用途:

jdk1.5及之前与Parallel Scavenge搭配使用

CMS的后备预案,在并发模式发生故障时使用

Parallel Old

Parallel Scavenge老年版本

使用多线程和标记整理算法

CMS

4、单独拎出CMS讲讲

CMS是一种以获取最短回收停顿时间为目标的收集器,基于标记清除算法实现,整个过程分为四个步骤:

初始标记、并发标记、重新标记、并发清除

初始标记、重新标记仍然需要STW,初始标记仅仅是标记一下GC Roots能直接关联到的对象,速度很快,并发标记阶段就是进行GC Roots Tracing的过程,重新标记则是修正在并发标记期间用户程序继续运作而导致标记产生变动的那一部分对象的标记记录。

由于耗时最长的并发标记和并发清除过程收集器线程都可以和用户线程一起工作,

缺点:

  • 对cpu资源敏感,会导致程序变慢,吞吐量降低

  • 无法处理浮动垃圾

  • 基于标记清除算法,大量空间碎片

针对后面两点解决方案:降低触发CMS的阈值,保证老年代有足够的空间

5、前沿垃圾回收器之一的G1

特点:

  • 分区概念 弱化分代,逻辑分代,物理不分代

  • 基于标记整理算法 不会产生空间碎片 分配大对象不会提前full gc

  • 充分利用cpu 多核条件下 缩短STW

  • 可以设置预设停顿时间

四个步骤

初始标记、并发标记、重新标记、混合回收

初始标记是标记从GC Root能直接关联到的对象,并且修改TAMS(Next Top at Next Start)的值,目的是为了让下一阶段用户程序运行时,能在正确Region中创建新对象,这个阶段需要STW但是耗时很短。并发标记阶段是从GC Root开始对堆中进行可达性分析,找出存活的对象,这个过程耗时较长,但是可以与用户线程并发执行。重新标记则是为了修正并发标记期间由于用户程序继续运作而导致标记产生变化的那一部分标记记录。最后在混合回收阶段根据用户期待的GC时间制定回收计划。

你说天长,我就递酒,咱们下期再见!

微信公众号:麦客子
关注可了解更多的Java相关知识。问题或建议,请公众号留言;
没有白走的路,只要认真走过,每一步就都算数。

免责声明:文章版权归原作者所有,其内容与观点不代表Unitimes立场,亦不构成任何投资意见或建议。

程序员

513

相关文章推荐

未登录头像

暂无评论