GC参数和垃圾收集器
1.串行收集器
-最古老、最稳定、效率高
-可能产生较长的停顿:只使用一个线程,所以在多核中表现不足
-XX:UserSerialGC启动串行收集器
-新生代,老年代使用串行回收
-新生代复制算法
-老年代标记-压缩
上图可知,在运行过程中,应用程序线程是由很多个的,而GC线程只有一个,GC过程中,应用程序暂停,直到GC结束,才开始重新运行。GC+时间,表示串行回收器,第一个图回收新生代,Full GC表示老年代的回收。
2.并行收集器
-ParNew
---- -XX:+UseParNewGC
--------新生代并行,老年代串行
-是串行Serial收集器新生代的并行版本
-复制算法
-多线程,需要多核支持
- -XX:ParallelGCThreads限制线程数量
并不是说多线程一定比单线程快,和cpu有关,如果是多核,大部分会比单线程快在单核cpu上,建议使用串行收集器。
GC ParNew表示的就是使用并行收集器
Parallel收集器
-类似ParNew
-新生代复制算法
-老年代 标记压缩
-更加关注吞吐量
- XX:+UseParallelGC
- --新生代使用Parallel收集器+老年代串行
- XX:+UseParalleOldlGC
- --新生代使用Parallel收集器+老年代并行
-XX:MaxGCPauseMills
- 一次GC的最大停顿时间,单位毫秒
- GC尽力保证回收时间不超过设定值
-XX:GCTimeRatio
- 0100的取值范围
- 垃圾收集时间占总时间的比
- 默认99,即最大允许1%时间做GC
这两个参数是矛盾的,因为停顿时间和吞吐量不可能同时调优
为什么这么说呢?因为垃圾回收的工作总量是一定的,就是需要这么多时间做这么多事情,我们可以安排它什么时候做gc这个事情,如果说我们把这个GC的频度提高,那么每次GC的停顿时间就会缩短,但是对于系统的整体性能来说,频繁地进行GC会使性能下降。为了提高系统性能,就要缩短GC次数,这样相对的每次GC的时间就会变长,即停顿时间变长。(可能存在错误,个人理解,欢迎指出错误)
3.CMS收集器
- Concurrent Mark Sweep 并发标记清除,能和应用程序(用户线程)一起执行,交替执行,停顿时间相对较少
- 标记清除算法
- 与标记压缩相比,并发阶段会降低吞吐量
- 老年代收集器(新生代使用ParNew)
- XX:+UseConcMarkSweepGC
CMS运行过程比较复杂,着重实现了标记的过程,可分为
--初始标记
-------标记根可以直接关联到的对象
-------速度快,产生全局停顿
--并发标记(和用户线程一起)
-------主要标记过程,标记全部对象
--重新标记(独占CPU,产生全局停顿)
-------由于并发标记时,用户线程依然运行,因此在正式清理前,还需要再做修正
--并发清除(和用户线程一起)
------基于重新标记结果,直接清理对象
发生全局停顿的时候,就在初始标记和重新标记。
这里使用并发清理不使用并发压缩,原因是,应用程序还在执行,如果采用并发压缩,需要整理内存空间,将正在使用的对象移位,这样可能会使应用程序出现问题,所以采用并发清理而不是压缩。
特点:
- 尽可能降低全局停顿
- 会影响系统整体吞吐量和性能
- 比如,在用户线程运行过程中,分一半CPU去做GC,系统性能在GC阶段,反应速度就下降一半
- 清理不彻底
- 因为在清理阶段,用户线程还在运行,会产生新的垃圾,无法清理
- 因为和用户线程一起运行,不能在空间快满时才清理
- -XX:CMSInitiatingOccupancyFraction 设置触发GC的阈值
- 如果不幸内存预留空间不够,就会引起concurrent mode failure
在清理的时候,试图去清理垃圾对象,但是在清理过程中,应用程序仍然在不断申请内存空间,导致内存不够用,引起concurrent mode failure,遇到这种错误,需要将应用程序全都暂停,使用串行收集器作为后备。
有关碎片:
- 标记清除和标记压缩
- 标记清除会在整理之后,内存空间有大量的碎片产生,标记压缩基本没有碎片,这样有碎片的影响空间分配,如果有对象申请连续的5个空间,在左图中是分配不了的。
- 为了解决碎片问题,可以在CMS GC之后,进行碎片整理,此时整理是要全局停顿的,因为整理需要移动对象在内存中的位置的,如果应用程序还在工作,那么可能引起应用程序出错。
GC参数整理
如果不对的地方,欢迎讨论指出