垃圾收集器
- 串行收集器 Serial开头的
- Serial
- Serial Old(MSC)
- 并行收集器 Parallel开头的
- ParNew
- Parallel Scavenge
- Parallel Old
- 并发收集器
- CMS (Concurrent Mark Sweep)
- G1(Garbage First)
- 图片中的问号位置
- JDK 1.7后有G1
GC算法是内存回收的方法论,GC收集器是内存回收的具体实现
Serial收集器
- 最基本,发展历史悠久,稳定
- 如名字,单线程收集器
- GC时,暂停所有的工作线程,直到GC结束
- 新生代(复制算法),老年代(标记-整理算法)都使用
- 虚拟机运行在Client模式时的默认新生代收集器
- 如下图,包括Serial和Serial Old
Serial Old收集器
- Serial收集器的老年代版本
- 使用标记-整理算法
- Client模式下,见Serial收集器
- Server模式下
- 在JDK 1.5之前,与Parallel Scanvenge配合使用
- 作为CMS的后备预案,发生Concurrent Model Failue时使用
ParNew收集器
- 新生代收集器
- Serial的多线程版本,沒有太多创新之处
- Server模式下,JVM首选的新生代收集器
- 只有ParNew能和老年代的CMS配合使用
- ParNew收集器是使用-XX:+UseConcMarkSweepGC选项的默认新生代收集器;也可以用-XX:+UseParNewGC选项来强制指定它
- 单CPU环境下,性能不会比Serial好。有线程切换的开销
Parallel Scanvenge收集器
- 新生代收集器
- 复制算法,并行的多线程
- 也叫吞吐量优先收集器
- 目标:达到一个可控制的吞吐量(Throughput)
- 吞吐量=运行用户代码时间/(运行用户代码时间 + GC时间)
- 停顿时间短,适合与用户交互的程序;高吞吐量,可以有效利用CPU时间,尽管完成计算任务,适合后台运算而不需要太多交互的任务
- 提供两个参数精确控制吞吐量
- -XX:MaxGCPauseMillis控制最大垃圾收集停顿时间
- -XX:GCTimeRatio设置吞吐量大小,0-100间,就是垃圾收集时间占总时间的比率。默认为99,则允许最大GC时间就占总时间的1%(即1/(1+99)).
- -XX:+UseAdaptiveSizePolicy,是个开关参数,打开后会自动调整新生代大小(-Xmn), Eden与Survivor比例(-XX:SurvivorRatio),晋升老年代对象年龄(-XX:PretenureSizeThreashold)等细节参数。这个参数也是Parallel Scavenge和ParNew的重要区别。
Parallel Old收集器
- Parallel Scavenge的老年代版本
- JDK 1.6后出现,此前,沒有跟Parallel Scavenge配合的老年代多线程收集器,只有使用Serial Old作为老年代收集器,其吞吐量优先的设计思路不能被很好的贯彻
CMS(Concurrent Mark Sweep)
The Concurrent Mark Sweep (CMS) collector (also referred to as the concurrent low pause collector) collects the tenured generation. It attempts to minimize the pauses due to garbage collection by doing most of the garbage collection work concurrently with the application threads.(http://www.oracle.com/technetwork/java/faq-140837.html)
- 目标:最短回收停顿时间
- 并发收集,低停顿,适合B/S架构,需要低延迟时间的应用需求
- 基于标记-清除算法
步骤
- 初始标记(停顿,initial checkpoint,标记GC Roots能关联的对象)
- 并发标记(GC Roots Tracing,此时用户线程可能会修改对象,标记会变动)
- 重新标记(停顿,标记变动的对象,但时间远比并发标记短)
- 并发清除
3个明显缺点
-
- CPU资源敏感。占用一部分CPU,程序整体变慢,总吞吐量降低
-
- 无法处理浮动垃圾(Floating Gargbage),要是CMS运行期间预留的内存无法满足程序需要,就会出现Concurrent Mode Failure(从而导致另一次Full GC),这时候就会启用Serial Old收集器作为备用进行老年代的垃圾收集.
-
- 内存空间碎片。提供-XX:+UseCMSCompactAtFullCollection参数,应用于在FULL GC后再进行一个碎片整理过程。-XX:CMSFullGCsBeforeCompaction,多少次不压缩的full gc后来一次带压缩的。
-
Phase 1 (Initial Checkpoint) involves stopping all the Java threads, marking all the objects directly reachable from the roots, and restarting the Java threads.
Phase 2 (Concurrent Marking) starts scanning from marked objects and transitively marks all objects reachable from the roots. The mutators are executing during the concurrent phases 2, 3, and 5 below and any objects allocated in the CMS generation during these phases (including promoted objects) are immediately marked as live.
Phase 3(Concurrent Precleaning): During the concurrent marking phase mutators may be modifying objects. Any object that has been modified since the start of the concurrent marking phase (and which was not subsequently scanned during that phase) must be rescanned. Phase 3 (Concurrent Precleaning) scans objects that have been modified concurrently. Due to continuing mutator activity the scanning for modified cards may be done multiple times.
Phase 4 (Final Checkpoint) is a stop-the-world phase. With mutators stopped the final marking is done by scanning objects reachable from the roots and by scanning any modified objects. Note that after this phase there may be objects that have been marked but are no longer live. Such objects will survive the current collection but will be collected on the next collection.
Phase 5 (Concurrent Sweep) collects dead objects. The collection of a dead object adds the space for the object to a free list for later allocation. Coalescing of dead objects may occur at this point. Note that live objects are not moved.
Phase 6 (Resetting) clears data structures in preparation for the next collection.
G1收集器
- 面向服务端应用
- 将堆划分为多个大小相等的独立区域(Region),保留分代,但不再是物理隔籬
- 特點
- 并行与并发。 并行,充分利用多核CPU或多个CPU来缩短STW时间;并发,保持用户线程继续执行
- 分代收集。对不同代的对象能够采用不同的方式去处理
- 空间整合。G1从整体看,是”标记-整理”算法,从局部(两个Region间)看,基于”复制算法”。意味着不会产生内存空间碎片
- 可预测的停顿。因为可以有计划地避免在整个Java堆中进行全域的垃圾收集。G1跟踪各个Region的垃圾堆积的价值大小,后台维护一个优先列表,每次根据运行的收集时间,优先回收价值最大的Region
GC收集器的选择
这部分内容来自http://www.javaranger.com/archives/1832
JVM给了三种选择:串行收集器、并行收集器、并发收集器,但是串行收集器只适用于小数据量的情况,所以这里的选择主要针对并行收集器和并发收集器。默认情况下,JDK5.0以前都是使用串行收集器,如果想使用其他收集器需要在启动时加入相应参数。JDK5.0以后,JVM会根据当前系统配置进行判断。
吞吐量优先的并行收集器
如上文所述,并行收集器主要以到达一定的吞吐量为目标,适用于科学技术和后台处理等。
典型配置:
java -Xmx3800m -Xms3800m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20
-XX:+UseParallelGC:选择垃圾收集器为并行收集器。此配置仅对年轻代有效。即上述配置下,年轻代使用并发收集,而年老代仍旧使用串行收集。
-XX:ParallelGCThreads=20:配置并行收集器的线程数,即:同时多少个线程一起进行垃圾回收。此值最好配置与处理器数目相等。
java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20 -XX:+UseParallelOldGC
-XX:+UseParallelOldGC:配置年老代垃圾收集方式为并行收集。JDK6.0支持对年老代并行收集。
java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:MaxGCPauseMillis=100
-XX:MaxGCPauseMillis=100:设置每次年轻代垃圾回收的最长时间,如果无法满足此时间,JVM会自动调整年轻代大小,以满足此值。
java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:MaxGCPauseMillis=100 -XX:+UseAdaptiveSizePolicy
-XX:+UseAdaptiveSizePolicy:设置此选项后,并行收集器会自动选择年轻代区大小和相应的Survivor区比例,以达到目标系统规定的最低相应时间或者收集频率等,此值建议使用并行收集器时,一直打开。
响应时间优先的并发收集器
如上文所述,并发收集器主要是保证系统的响应时间,减少垃圾收集时的停顿时间。适用于应用服务器、电信领域等。
典型配置:
java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:ParallelGCThreads=20 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC
-XX:+UseConcMarkSweepGC:设置年老代为并发收集。测试中配置这个以后,-XX:NewRatio=4的配置失效了,原因不明。所以,此时年轻代大小最好用-Xmn设置。
-XX:+UseParNewGC:设置年轻代为并行收集。可与CMS收集同时使用。JDK5.0以上,JVM会根据系统配置自行设置,所以无需再设置此值。
java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseConcMarkSweepGC -XX:CMSFullGCsBeforeCompaction=5 -XX:+UseCMSCompactAtFullCollection
-XX:CMSFullGCsBeforeCompaction:由于并发收集器不对内存空间进行压缩、整理,所以运行一段时间以后会产生“碎片”,使得运行效率降低。此值设置运行多少次GC以后对内存空间进行压缩、整理。
-XX:+UseCMSCompactAtFullCollection:打开对年老代的压缩。可能会影响性能,但是可以消除碎片