重新认识垃圾回收器

什么是垃圾回收器?

随着系统的不断运行,系统会时不时的出现卡顿的现象,这是由于我们在堆内存中创建的对象已经达到了上限,这个时候如果我们不进行GC的话 系统将会抛出异常OOM,所以我们在进行GC的过程中对系统需要执行STW,这个时候就会在一定程度上影响到系统的执行,我们会把市区引用的对象进行标记回收,这个过程称为垃圾回收,执行者就是垃圾回收器。

基于JVM运行的系统最怕什么?

JVM运行的时候最核心的内存区域就是堆内存,堆内存的分配是否合理直接影响到了系统的STW的次数和系统的执行效率,堆内存主要按照概念性的划分为新生代或者是年轻代和老年代,我们创建的新的对象会分配到新生代中,随着新生代的内存不足以放下创建的新对象就会执行新生代的GC。

新生代(年轻代)主要分为Edon和两个S区域,比例为8:1:1,当我们创建的新生代优先分配到Edon,当Edon区域的对象不足以存放新的对象的时候此时新生代就是触发一次新生代GC,此时系统会Stop The World,系统会卡顿几十ms,从感知上对用户的影响并不是很大。我们也可以忽略针对新生代的系统调优,新生代的GC采用的垃圾回收器是ParNew,是多线程执行垃圾回收,针对多核CPU有明显的效果但是如果是单线程的系统不建议使用,反而会占用CPU的资源。我们可以在系统启用的时候设置我们采用哪种垃圾回收器。新生代的GC主要流程是新创建的对象会优先分配到Edon中,当内存不够的时候我们会STW,从GC Roots触发标记直接引用和间接引用的对象,我们在新生代中创建的对象主要分为两种一种是静态变量一种是局部变量在方法中创建的对象,一旦方法执行完成 这类的对象就变成了了没有引用的对象需要被回收,然而新生代中90%以上存在的都是这类的对象,我们将部分存活的Edon和S1区域存活的对象复制到S2区域,将Edon和S1区域的内存进行清理完毕,新生代GC采用的复制算法,对系统的影响不是很大。

什么情况下新生代GC对系统影响很大?

当你的系统部署到大内存的机器上的时候,比如你的机器是32核64G的机器,此时新生代分配的内存达到了几十G的情况下,针对一些kafka和ES的系统可能每秒产生几十万的对象,这个时候可能进行GC的消耗的时候就会达到几秒以上,这个时候对客户感知上就存在一定的冲击,这个时候如果我们采用G1垃圾回收器,将GC的时候控制在几十ms之内,减少感知上的冲击,G1就是比较适用于处理大内存机器的情况。

频次的老年代的GC。

什么情况下对象会进入到老年代?

1.新生代GC之后也不足以存放新生成的对象。

2.新生代GC之后S1区域不足存放短期存活的对象。

3.针对一些系统需要长期存在的组件的对象需要长期存活的大年龄的对象。

4.动态年龄判断将同龄年龄以上的对象存入到老年代。

老年代为什么GC很慢?

老年代的GC主要分为四步:初始标记,并发标记,重新标记,并发处理,整理碎片。G1和CMS大致步骤都是以上四步。由于老年代中存活的对象很多,在初始标记和重新标记的时候需要Stop The World,初始标记会从GC Roots 出发标记直接饮用的对象,重新标记会依赖并发标记的记录进行标记,这两个阶段由于存活的对象很多标记很耗时并且是单线程执行,并发标记和并发处理采用的是多线程,并发标记会深度追踪间接引用的对象,并不会Stop The World ,允许系统继续执行,再次进入老年代的对象会存放到浮动的内存中,这也就是为什么老年代达到82%的时候就会触发GC,会预留一部分的内存给在并发标记的过程中产生的新对象,并发标记的过程中会记录那些是重新生成的对象那些是垃圾对象供重新标记的时候作为参考,并发清理同样允许系统执行不需要STW,会将标记的对象进行清理,由于不像新生代那样整个的内存区域清理,老年代在清理的时候内存对象并不是连续的也会消耗一定的时间,清理之后还需要整理碎片。所以说老年代的GC要比新生代的GC慢10陪多。如果老年代GC之后还不足以存放就是抛出OOM,直接STW采用Serial Old进行重新标记清理。所以说我们要避免国过多的老年代的GC。

你可能感兴趣的:(重新认识垃圾回收器)