1. JVM 垃圾回收器简介及Stop the World问题
1.1. 垃圾回收器简介
在新生代和老年代进行垃圾回收的时候,都是要用垃圾回收器进行回收的,不同的区域用不同的垃圾回收器。
1.1.1. Serial和Serial Old垃圾回收器
分别用来回收新生代和老年代的垃圾对象,工作原理就是单线程运行,垃圾回收的时候会停止自己的系统的其他工作线程,让系统直接卡死不动,然后垃圾回收,后台Java系统现在一般几乎不会使用。
1.1.2. ParNew和CMS垃圾回收器
ParNew是现在一般用在新生代的垃圾回收器,CMS是用在老年代的垃圾回收器,都是多线程并发的机制,性能更好,一般是线上生产系统的标配组合。
1.1.3. G1垃圾回收器
统一收集新生代和老年代,采用了更加优秀的算法和设计机制。
1.2. Stop the World问题
1.2.1. 回顾新生代 GC 流程
新生代快满的时候,发生垃圾回收,会将存活对象,放到 空白的S区,两块 S区 交替使用,如下图所示。
1.2.2. GC 的时候可以创建新对象吗
之前介绍垃圾回收的时候,没有提到是否可以创建对象,在这里来介绍一下。
假如 GC 期间,还可以创建对象,会有什么问题呢?
新生代使用复制算法,GC 过程中,回收线程将存活对象移动到 Survivor区,这时候创建新的对象,会放在 Eden区,当要回收的时候可能会有新创建的对象,还有重新处理,会增加回收的复杂性,成本极高,很难做到。所以回收过程中可以创建新对象是非常不合适的。
1.2.3. Stop the World问题
什么是Stop the World
在垃圾回收的时候,让垃圾回收器专心致志的工作,所以不能让Java系统继续创建对象,此时JVM会直接进入Stop the World
状态。
JVM会直接停止Java系统的所有工作线程,让业务系统的代码不再运行!然后垃圾回收线程可以专心致志的进行垃圾回收的工作。
系统不再创建新的对象时,同时垃圾回收线程会尽快完成垃圾回收的工作,标记和转移Eden以及Survivor2的存活对象到Survivor1中,一次性回收掉Eden和Survivor2区域。
垃圾回收完毕,业务系统的工作线程就可以继续运行了,继续在Eden中创建新的对象。
Stop the World
会有什么影响
假如Minor GC
要运行100ms,则会导致系统直接停顿100ms不能处理任何请求。在这100ms期间用户发起的所有请求都会出现短暂的卡顿,因为系统的工作线程不在运行,不能处理请求。
可以思考一下,因为内存分配不合理,导致对象频繁进入老年代,平均七八分钟一次Full GC
,而Full GC
是最慢的,一些情况下一次回收要进行几秒钟,甚至几十秒,极端场景也可能是几分钟。
一旦频繁的Full GC
,系统每隔七八分钟就卡死几十秒。在这期间任何用户的请求全部无法处理,用户看到的都是系统超时之类的提示,这会导致使用体验极差。
所以,无论是新生代GC还是老年代GC,都尽量不要频率过高,也避免持续时间过长,避免影响系统正常运行,这是使用JVM过程中一个最需要优化的地方。