常见的垃圾收集器分为串行、吞吐量优先和响应时间优先三种。
串行:Serial
这是1.8 默认的GC器 ,主要设置的参数为:
-XX:+UseParallelGC ~ -XX:+UseParallelOldGC
新生复制,老年标记整理
-XX:+UseAdaptiveSizePolicy
自适应调整新生代大小
-XX:GCTimeRatio=ratio
公式 1 / (1 + ratio) ratio默认值是99 ,也就是工作100分钟内,只有1分钟可以用于垃圾回收。如果达不到整个目标,ParallelGC会调增大堆的大小, 垃圾回收次数减少 ,以此来提高吞吐量。一般ratio设置为19。
-XX:MaxGCPauseMillis=ms
最大暂停时间也就是垃圾回收的时间,默认200ms
-XX:ParallelGCThreads=n
控制垃圾回收线程数量
工作流程与串行的区别是开启多个垃圾回收线程来回收,数量由电脑的CPU核数决定,同样用户线程被阻塞。特点是多线程收集,让单位时间内STW时间最短 即收集次数少时间可以长点,比如一小时内2次,一次0.2秒。
设置的参数为:
-XX:+UseConcMarkSweepGC ~ -XX:+UseParNewGC ~ SerialOld --> CMS工作在老年代,使用标记清除算法。ParNew工作在新生地,ParNew是Serial的多线程版本。但CMS有时候会发生并发失败问题,这时候老年代垃圾回收器变为SerialOld 。
-XX:ParallelGCThreads=n ~ -XX:ConcGCThreads=threads:并发线程数一般设置为并行线程数的1/4,比如4核就设置成1。1个线程来做垃圾回收,另外3个继续执行用户线程。
-XX:CMSInitiatingOccupancyFraction=percent 执行CMS回收的内存占比,值越小执行垃圾回收时机越早。
-XX:+CMSScavengeBeforeRemark 在重新标记前做一些新生代的垃圾回收。因为重新标记时,新生代的对象会引用老年代的对象,标记时需要扫描整个堆,然后通过新生代引用扫描到老年代对象并作可达性分析。这种场景下新生代对象非常多并且很多会作为垃圾对象被回收,再根据新生代对象引用找到老年代对象;相当于在回收之前多做了无用的查找,这时可以使用这个参数,使用新生代存活对象变少,减轻重新标记的压力。
工作流程是假设4核CPU并行执行4个线程。老年代内存不足,用户线程在安全点停下来了。先进行初始标记,标记一些GCroots对象,这时候用户线程被阻塞。下一步是并发标记,用户线程和垃圾回收线程并发执行。第三步是重新标记,因为并发标记时用户线程继续执行,可能会产生新的对象,或者改变对象的一些引用。最后是并发清理,但这次清理不能回收同时产生的垃圾对象(浮动垃圾),浮动垃圾只能等到下一次垃圾回收时再清理,使用上面第三个参数调整。
CMS使用的标记清楚算法,自然会产生大量内存碎片。将来分配对象时,当新生代内存不够时,老年代内存由于碎片过多也不足,就会造成并发失败,这时候垃圾回收器会退化为SerialOld,垃圾回收时间会剧增。