jvm垃圾回收
垃圾收集器
- Serial(新生代,老年代)收集器
- 是一个单线程收集器(不是只能使用一个CPU);在进行垃圾收集时,必须暂停其他所有的工作线程,直到收集结束
- 新生代采用复制算法,stop-the-world
- 老年代采用标记-整理算法,stop-the-world
- 简单高效,client模式下默认的新生代收集器
- ParNew(新生代)
- ParNew收集器是Serial收集器的多线程版本
- 新生代采用复制算法,stop-the-world
- 它是运行在Server模式下的首选新生代收集器
- 除了Serial收集器外,只有它能和CMS收集器配合工作
- Parallel Scanvenge(新生代,老年代)收集器
- 类似ParNew,但是更加关注吞吐量(运行用户代码时间 / (运行用户代码时间 + 垃圾收集时间))。目标是:达到一个可以控制吞吐量的收集器
- 停顿时间和吞吐量不可能同时调优;我们一方面希望吞吐量高,一方面希望停顿时间少,其实这很矛盾。因为在GC的时候,垃圾回收的工作总量是不会变的,如果停顿时间少,那么频率就会提高;提高频率,说明就会频繁的GC,那吞吐量就会减少,性能就会降低。
- 老年代采用标记-整理算法,jdk7、jdk8 默认使用该收集器作为老年代收集器
- CMS收集器(老年代):(Concurrent Mark Sweep:并发标记清除老年代收集器)
- 一种以获得最短回收停顿时间为目标的收集器,适用于互联网站或者B/S系统的服务上
- 初始标记(stop-the-world):只标记一下GC Roots能直接关联的对象,速度很快。
- 并发标记(和用户线程一起):主要标记过程,标记全部对象
- 重新标记(stop-the-world):由于并发标记时,用户线程依然运行,因此在正式清理前在做修正
- 并发清除(和用户线程一起):基于标记结果,直接清理对象
- 并发收集,低停顿
- G1收集器
- 是当今收集器发展的最前沿成功之一,对垃圾回收进行了划分优先级的操作,这种有优先级的区域回收方式保证了它的高效率
- 最大的优点是结合了空间整合,不会产生大量碎片,也降低了进行GC的频率
- 让使用者明确指定停顿时间
- jdk9默认收集器
GC算法
- 什么样的对象需要回收:
- 对象到GC Roots没有引用链,对象不可用,需要回收。
- 什么对象可以作为GC Roots的对象
- 虚拟机栈中引用的对象
- 方法区中类静态属性引用的对象
- 方法区中常量引用的对象
- 本地方法栈中JNI(native方法)引用对象
- 有哪些GC算法
- 标记-清除算法
- 遍及所有要回收的对象,标记完成后统一回收所有被标记的对象
- 缺点是标记和清除两个过程效率低
- 清除后会产生空间碎片,导致大对象无法获取足够的空间,从而提前出发垃圾回收
- 复制算法
- 将内存分为两块,每次只用其中一块,将不回收的对象存入另一块,将原来半块全部回收
- 实现简单,效率高,但内存代价高
- 大多是对象存活时间很短,不需要1:1划分区域
- 一块较大的Eden和2个survivor空间,每次使用Eden和一个Survivor,再将存活的对象复制到另一块Survivor区
- Survivor去空间不够是需要老年代进行担保
- 标记整理法
- 标记需要回收对象,将存活对象移动到内存一端,然后将其他对象回收
- 分代收集算法
- 将堆分为新生代,和老年代
- 新生代每次只有少量对象存活,用复制算法,只需要付出复制少量存活的对象成本
- 老年代对象存货效率高,用标记-清除,或者标记-整理法
- 标记-清除算法
Minor GC(Young GC),Full GC(Major GC)
- Minor gc
- 新生代上的gc,当新生代的Eden区满的时候触发
- Full gc
- 经过minor gc之后存活的一部分对象会进入老年代,如果老年代空间不足时,会触发full gc
JDK1.7之前永久代空间不足也会触发Full GC
收集器之间的搭配使用
JVM收集器设置
-XX:+UseSerialGC:在新生代和老年代使用串行收集器
-XX:+UseParNewGC:在新生代使用并行收集器】
-XX:+UseParallelGC :新生代使用并行回收收集器,更加关注吞吐量
-XX:+UseParallelOldGC:老年代使用并行回收收集器
-XX:ParallelGCThreads:设置用于垃圾回收的线程数
-XX:+UseConcMarkSweepGC:新生代使用并行收集器,老年代使用CMS+串行收集器
-XX:ParallelCMSThreads:设定CMS的线程数量
-XX:+UseG1GC:启用G1垃圾回收器