垃圾回收器
垃圾回收器是内存回收的具体实现,Java有四类垃圾回收器,分别是:
- Serial Garbage Collector
- Parallel Garbage Collector
- CMS Garbage Collector
- G1 Garbage Collector
1 | // 通过如下命令可以查看 JVM 默认的垃圾回收器 |
串行垃圾回收器
串行垃圾回收器是JVM Client模式下的默认GC,只使用一个单独的线程进行垃圾回收,垃圾回收时会冻结所有应用程序的线程,垃圾回收期间程序暂停的时间较长
Serial GC
Serial GC为新生代的垃圾搜集器,采用复制回收算法。Java中所有新产生的对象都在Yong区中的Eden区,当Eden区的大小不足以容纳新生的对象或对象大小超过了PretenureSizeThreshold的参数配置大小 ,对象只能在Old区分配。当Eden区满后会触发Minor GC ,触法Minor GC前需要检查老年代的连续空间是否大于新生代总大小或者历届晋升对象的平均大小,若满足就会进行Minor GC,否则将进行Full GC。Minor GC除了清除Eden区的非活跃对象外,还会把Survivor区一些老对象移动到Old区,老对象的定义通过配置MaxTenuringThreshold大小来控制,1.当对象在Survivor区的存活次数达到MaxTenuringThreshold的大小则会被移动到Old区。 2.当Survivor区中相同年龄大小的所有对象大小总和超过了Survivor区空间的一半(默认 -XX:TargetSurvivorRatio=50)则会被移动到Old区
Serial Old GC
Serial Old GC 为老年代搜集器,使用“标记-整理”算法,此GC不能够主动配置。1.当CMS收集器发生错误的时候使用。2.配合其他GC使用
并行垃圾回收器
Parallel GC 根据Minor GC 和 Full GC的不同分为三种,分别为:ParNewGC、ParallelGC,ParallelGC。并行垃圾回收器以多线程的方式进行回收
ParNewGC
属于新生代的GC,此垃圾搜集器的工作方式与Serial GC类似,只不过它是多线程的,垃圾回收器工作的时候同样需要停止程序的所有线程
ParNewGC组合参数
- PretenureSizeThreshold :此参数表示当对象的大小超过此值则直接进入Old区,只对Serial和ParNew两款收集器有效
- UseAdaptiveSizePolicy:当这个参数打开之后,就不需要手工指定新生代的大小(-Xmn)、Eden与Survivor区的比例(-XX:SurvivorRatio)、晋升老年代对象年龄(-XX:PretenureSizeThreshold )等细节参数了
Parallel GC
JVM Server模式下默认的GC方式,即Parallel Scavenge,属于新生代GC。此垃圾搜集器与Par NewGC类似,不同地方在于Parallel Scavenge关注点是程序的吞吐量
吞吐量与响应时间
- 吞吐量:运行用户代码时间 /(运行用户代码时间 + 垃圾收集时间),吞吐量高适合后台密集运算的程序
- 响应时间:程序停顿时间的大小,响应时间短适合应用与用户交互的程序
Parallel GC的组合参数
- MaxGCPausedMillis:垃圾回收器将尽可能在此时间内完成完成内存回收,关注停顿时间
- GCTimeRatio:设置垃圾搜集时间占总时间的比值,即:1-吞吐量,关注吞吐量
- ParallelGCThreads:指定回收线程数
ParallelOldGC
属于老年代GC,以多线程的方式使用“标记-整理”算法
并发标记清除垃圾回收器
CMS(Concurrent Mark Sweep)收集器是以响应时间为目标的收集器,是老年代的GC,基于“标记-清除”算法。对于B/S系统的服务端,需要重视服务的响应速度。CMS的触发规则是检查Old区的使用率(设置参数为:CMSInitiatingOccupancyFraction),当达到一定的使用率则会触发CMS GC,当CMS GC正在进行的时候,若此时JVM正在向Old区申请内存,Old区内存不够则申请会失败并会触发Full GC
CMS过程
- Initial Mark: 初始化标记,标记对象根路径直接关联的对象,需要终止程序所有线程(Stop The World,单线程)
- Concurrent Mark: 并发标记,追踪根路径可达的对象
- Concurrent precleaning: 并发预处理,查找并发标记阶段进入老年代的对象,减少下一阶段的停顿时间
- Remark:重新标记,扫描从根对象开始向下追溯,并处理关联对象,需要终止程序所有线程(Stop The World,多线程)
- Concurrent sweeping: 并发清理垃圾对象
- Concurrent reset: 并发重置,等待下一次垃圾回收
CMS使用
CMS收集方式能够减少程序停顿时间。“标记-清除”算法会产生大量的内存空间碎片
CMS组合参数
- UseCMSCompactAtFullCollection:Full GC 后进行一次碎片整理,整理过程会Stop The World
- CMSFullGCsBeforeCompaction: 设置进行几次Full GC后进行碎片整理
- ParallelCMSThreads:设置CMS线程数量
- ExplicitGCInvokesConcurrent :设置当显示GC调用、只会触发CMS,不会进行Full GC
G1垃圾收集器
G1垃圾回收器,将Java堆分为多个大小相等的区域(region),新生代与老年代对象耦合在一起
G1 GC过程
- 标记阶段:初始化标记对象,并进行Minor GC ,此阶段会Stop The World
2. Root Region Scanning:回收Survivor区,必须在Yong GC之前完成
3. Concurrent Marking:在整个堆中进行并发标记,此过程会被Yong GC打断,若发现区域存在垃圾对象则直接进行回收,此阶段会进行每个区域中存活对象的比例统计
4. Remark:再标记用来收集在并发阶段产生的垃圾对象,效率高于CMS,此阶段会Stop The World
5. Copy/Clean up:多线程消除垃圾对象,将存活对象移动到新区域,此阶段会Stop The World
6. After Copy/Clean
G1 VS CMS
- G1 使用“标记-整理”算法,不会出现内存碎片,分配大对象不会因为找不到连续的空间进行GC
- 可预测停顿,G1能够建立可预测的停顿时间模型
GC组合使用
不同GC是可以进行组合使用的
People do not lack strength, they lack will. - Andrew Laeddis