GC回收策略有:复制、标记清除、标记整理。
heap区 | 算法实现 | 效率 | 空间 | 内存碎片 | 缺点 | |
复制 | 新生代 | Serial & ParNew & Parallel Scavenge | 高 | 需要预留 | 无 | 只适合对象存活率低 |
标记清除 | 老年代 | CMS | 一般 | 无需预留 | 有 | 适合存活率高 |
标记整理 | 老年代 | Serial Old & Parallel Old | 最差 | 无需预留 | 无 | 触发几率低 |
GC发生在不同的区域又称为不同的GC:
1)Minor GC:当伊甸区达到指定值的时候触发,清理新生代;
2)Major GC:当老年代到达指定阈值的时候触发,清理老年代(一般也会触发Minor GC,不同的GC回收器策略各不相同);
3)Full GC:当前两个GC触发之后,内存仍然不足或者方法区满了;则会触发Full GC,清理内存对象空间包括方法区。
CMS(Concurrent Mark Sweep)并发标记清除,优势是以获取最小的系统停顿时间为目的设计的;缺点也显而易见在牺牲更少的停顿时间的同时并发线程会占用系统资源,与用户线程同时工作。
CMS的执行阶段:
1.初始标记阶段(STW):根据可达性分析,标记GC ROOT能直接关联的对象;只是标记第一层直接引用。
插一句什么是GC ROOT的对象(与我们编程有关的也就是前三种):
Class-系统加载的类对象,自定义的类加载器加载的类,如果没有直接引用也不是root对象。
Thread-活着的线程。
Stack Local-java方法的local变量或者参数(栈中直接引用的对象)。
JNI Local-JNI方法的local 变量。
JNI Global-全局JNI引用。
Monitor Used-用于同步的监控对象。
Held by JVM-JVM自己预留的对象用于GC保留的对象。
2.并发标记:由前一阶段标记过的对象出发,所有可到达的对象都在本阶段中标记。
3.并发预清理:此阶段从新生代晋升的对象、新分配到老年代的对象以及在并发阶段被修改的对象。
下面盗个图:
通过触发一次可终止的Minor GC减少重新标记的停顿时间。
这个地方不太了解的可以看看(http://www.cnblogs.com/littleLord/p/5380624.html)尽信书不如无书!
还是要有自己的思考和实践。
4.重标记(STW):对新产生的对象做重新标记,同样STOP THE WORLD,但是大部分工作前期已经做过
了,这次时间相对比较短暂。
5.并发清理:用户线程被重新启动,同时清理无效对象。思考一下,通过根对象标记强引用对象,最后清除
是未标记的对象。
6.重置:CMS清除内部状态,为下次回收准备。
CMS存在的问题:
1.上面说的并发标记占用系统资源,CMS默认回收并发数 (CPU数量+3)/4。保证并发数量不会占用过多资源。
2.并发清除之后产生的新对象不在此次清理范围,称为“浮动垃圾”。
3.CMS是一种并发标记的标记清理,所以清理就会有内存碎片;还是需要定期的Full GC整理空间。