一、判断对象是否存在引用:
1、引用计数法算法:每当一个地方引用该对象,计数器加1,引用失效时,计数器减1,计数器为0即不可能再被引用(缺点:若存在两个对象互相引用且没有地方引用到他们时,将不会被回收,所以几乎不使用这种方法)
2、可达性分析算法:通过一系列GC Roots对象作为起始点,从这些节点开始向下搜索,搜索走过的路径称为引用链,当一个对象和引用链没有相连时,就是可回收的
(GC Roots对象包括:虚拟机栈即栈帧中的本地变量表中引用的对象、方法去中类静态属性引用的对象、方法去中常量引用的对象、本地方法栈中JNI即一般说的Native方法引用的对象)
补充四种类型引用:
强引用:最普遍,不赘述
软引用:有用但并非必需,在系统将要发生内存溢出异常之前,将会把它列进回收范围之中进行第二次回收
弱引用:只能生存到下一次垃圾收集发生之前
虚引用:唯一目的是用来在这个对象被收集器回收时收到一个系统通知
上述四个引用强度依次减弱
二、回收方法区:
方法区(永久代)主要回收:废弃常量和无用的类;
废弃常量比如没有任何String对象引用常量池中的“hello”字符串,该字面量将会被清理出常量池;
无用的类必须满足:类中所有实例都已经被回收,加载类的ClassLoader已经被回收、类对应的java.lang.Class对象没有任何地方被引用,无法在任何地方通过反射访问该类的方法。
三、垃圾收集算法:
1、标记-清除算法,即简单的标记清除,不做其他动作
2、复制算法:将内存容量分为相等两块,一块使用,一块保留,清除时将使用那块不用清除的移动到保留块,然后清除使用块,原先保留的作为使用块,依次循环(实现简单,运行高效,代价是内存缩小为原来一半)
3、标记-整理算法:类似标记-清除,但是有让所有存活对象向一端移动,适合老年代。
4、分代收集算法:将对分为新生代和老年代,新生代用复制算法,老年代用标记-清除或者标记-整理算法
四、HotSpot虚拟机中对于垃圾回收算法的改进:
(枚举根节点)使用OopMap数据结构将应用位置记录下来
(设置安全点)让线程跑到安全点停顿下来,有两种方法:1、抢先式中断,先中断所有线程,没有到达安全点的线程恢复,让它跑到安全点中断(现在几乎不用);2、主动式中断,设置个标志,各线程主动轮询这个标志,发现中断标志就中断挂起
(设置安全区域)指在一段代码片段之中,引用关系不会发生变化
五、垃圾收集器:
Serial收集器:单线程新生代收集器,工作室必须暂停其他所有的工作线程,适合于虚拟机运行在Client模式下的新生代收集器
ParNew收集器:即Serial收集器的多线程版本,适用于虚拟机运行在Server模式下,默认开启收集线程与CPU个数相同
Parallel Scavenge收集器:新生代收集器,目标是打到一个可控制的吞吐量(运行用户代码时间/(运行用户代码时间/垃圾收集时间)),它有两个参数用于精确控制吞吐量:-XX:ManGcPauseMillis(控制最大垃圾收集停顿时间(用新生代空间来换))、-XX:MaxTimeRatio(直接设置吞吐量大小),此外,还有一个参数-XX:+UseAdaptiveSizePolicy用于打开GC自适应调节策略(自动动态调整上面两参数)
Serial Old收集器:老年代收集器,单线程,使用“标记-整理”算法,也是适用于Client模式下,
Parallel Old收集器:老年代,使用多线程和“标记-整理”算法
CMS收集器:老年代,目标是获取最短回收停顿时间为目标的收集器,基于“标记-清除”算法,分别为:
初始标记:暂停所有线程,标记GC Roots能直接关联到的对象。
并发标记:进行GC Roots Tracing过程
重新标记:暂停所有线程,修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,停顿时间比初始标记稍长但是比并发标记短多了
并发清除
CMS三个缺点:
1、对CPU资源非常敏感,并发阶段占用了一部分CPU资源,默认启动回收线程数是(CPU数量+3)/4;
2、无法处理浮动垃圾,就是并发清理时还有在产生垃圾,这一部分垃圾要下次才能回收
3、基于“标记-清除”算法,会产生大量空间碎片,有两个参数可以设置:-XX:+UseCMSCompactAtFullCollection,默认是开启的,用于CMS顶不住要进行FullGC时开启内存碎片合并整理,这个过程无法并发,停顿时间变长;-XX:CMSFullGCsBeforeCompaction,用于设置执行多少次不压缩的Full GC后,跟着来一次带压缩的。
G1收集器:新生代和老年代
特点:
1、并行与并发
2、分代收集
3、空间整合(采用“标记-整理”算法)
4、可预测的停顿
新生代GC(Minor GC)
老年代GC(Major GC / Full GC)
对象优先在新生代分配,大对象直接进去老年代,长期存活的对象将进入老年代(默认15岁但并不一定)