JVM调优2---垃圾回收算法及垃圾回收器
1. 常见的垃圾回收算法
1.1 引用计数法
历史最悠久的一种算法, 现在仍有语言使用。
假设有对象A, 有任何一个对象对A进行引用, A的引用数+1, 如果对象A的引用为0, 则表示A没有被引用, 可以被回收。
缺点: 无法解决循环引用的问题, 出现循环引用时垃圾回收无法回收两个对象。
public class A{
public B b;
}
public class B{
public A a;
}
public class test{
... main (){
A a = new A();
B b = new B();
a.b = b;
b.a = a;
a = null;
b = null;
}
}
以上 a,b 虽然都为null,但是因为存在循环引用,所以GC无法回收
1.2 标记-清除算法
标记: 从根节点开始标记引用的对象
清除:未被标记引用的对象就是垃圾对象, 可以被清理
GC未开始工作之前所有对象是未标记状态, 一旦发生内存空间耗尽,JVM将会终止应用程序的运行开启GC线程,然后根据根搜索算法开始标记工作。
标记完成后将未被标记的对象进行清理, 清理完成将所有对象取消标记,JVM线程重新开始正常工作。
缺点: 1. 效率较低, 标记和清除两个动作都需要循环遍历所有对象,且在GC执行时(标记清除)需要将jvm现有进程停掉, 影响性
2. 标记清除算法整理出来的内存碎片化比较严重,回收的对象存在于内存的各个角落,所以清理出来的内存是不连贯的。
1.3 标记-压缩算法
在标记清除算法之上做了改进。 从根节点开始对对象的引用进行标记, 在清理阶段,将存活的对象压缩到内存的一段, 然后清理边界以外的垃圾, 从而解决了碎片化问题。
缺点: 存在对象移动这个操作, 效率低
优点: 解决了内存碎片化问题
1.4 复制算法
将原有内存空间一分为二, 每次只使用一半的内存, 当进行GC回收时, 将当前已使用空间存活的对象复制到另一半内存, 再将当前的内存一次性清除。
缺点: 当内存中垃圾比较多, 存活对象较少时适用。 但是当存活对象较多时, 需要产生的复制则比较多, 则不适用。
jvm年轻代内存空间
使用复制算法实现垃圾回收机制
JVM内存中, 年轻代分为 Eden区,Survior(from), Survior(to), 比例大小8:1:1
1、GC开始之前,对象只会存在于Eden区和Survior(from)区中, to区是空的
2、GC开始后, Eden区中存活的对象会被复制到to, 而from中对象存活的对象会根据他们的年龄至决定去向,达到一定范围就会移到老年区,没有的会移动到to区。
3、经过这次GC, from区会被清空,这时候from和to的角色互换, 等待执行下一次GC任务。
1.5 分代算法
现在大多是虚拟机采用这种算法, 根据对象的生命周期将堆内存分为年轻代和老年代。
年轻代产生的垃圾较多, 存活对象较少,适用于复制算法。
而老年代中的存活对象较多,垃圾较少,则适合于标记压缩算法或者标记清除算法。
2. 垃圾收集器以及内存分配
2.1 串行垃圾收集器
单线程进行垃圾回收, 垃圾回收时只有一个线程在工作, java应用中的所有线程都需要暂停, 等待垃圾回收完成。对于交互性较强的应用,这种垃圾回收器是不能接受的。
GC日志信息解读:
-
DefNew
表示串行垃圾收集器
4416k->512k(4928)
4416表示gc前占有4416k大小, 512表示gc后占有512k内存,4928表示总大小。 -
FullGC
表示内存空间全部(年轻代,老年代,Mataspace代)进行GC
2.2 并行垃圾收集器
在串行垃圾收集器的基础之上做了改进, 将单线程改为使用多线程进行垃圾回收,缩短了垃圾回收的时间。(这里是指并行能力较强的机器)
当然, 并行垃圾收集器工作过程中也会暂停应用程序,只是并行速度更快些,暂停的时间也就更短。
2.2.1 ParNew垃圾收集器
ParNew垃圾收集器是运行在年轻代上的, 只是将串行的垃圾收集器编程了并行。
-XX:+UserParNewGC 设置在年轻代上使用ParNew回收器, 老年代使用的依然是串行收集器。
- ParNew
表示并行垃圾收集器
2.2.2 ParllelGC垃圾收集器
和ParNewGC收集器一样, 在此基础上新增了两个和系统吞吐量相关的参数。
- -XX:+UseParllelGC 新生代使用ParllelGC收集器
- -XX:+UseParallelOldGC 老年代使用
- -XX:+MaxGCPauseMillis=100 设置GC的最大停顿时间
2.3 CMS垃圾收集器
CMS全称Concurrent Mark Sweep, 是一款并发的,标记-清除算法的垃圾回收器, 该回收器,该回收器是针对老年代垃圾回收的, 通过参数: -XX:+UseConcMarkSweepGC进行设置。
2.4 G1垃圾收集器
G1垃圾收集器是在jdk1.7中正式使用的全新的垃圾收集器
原理: G1垃圾收集器取消了物理上的分代,取之是将其划分成若干个区域, 这些区域在逻辑上分为老年代和年轻代区域。
3. 可视化GC日志分析工具
-XX:+PrintGCDetails可以对GC日志进行打印
使用在线工具https://gceasy.io/分析
Throughout:吞吐量, 吞吐量目标需要达到90%, 越高越好。