前言:
(1). 判断对象存活的两种方式(引用计数算法、枚举根节点做可达性分析)
(2). 标记阶段(引用计数法、枚举根节点做可达性分析)
(3). 清除阶段(复制算法、标记清除算法、标记整理(压缩)算法、分代收集、增量收集算法、分区算法)
①. 引用计数法
①. 原理:假设有一个对象A,任何一个对象对A的引用,那么对象A的引用计数器+1,当引用失败时,对象A的引用计数器就-1,如果对象A的计数器的值为0,就说明对象A没有引用了,可以被回收
②. 最大的缺陷:无法解决循环引用的问题,gc永远都清除不了(这也是引用计数法被淘汰的原因)
③. 代码展示:
/** * -XX:+PrintGCDetails * 证明:java使用的不是引用计数算法 */ public class RefCountGC { //这个成员属性唯一的作用就是占用一点内存 private byte[] bigSize = new byte[5 * 1024 * 1024];//5MB Object reference = null; public static void main(String[] args) { RefCountGC obj1 = new RefCountGC(); RefCountGC obj2 = new RefCountGC(); obj1.reference = obj2; obj2.reference = obj1; obj1 = null; obj2 = null; //显式的执行垃圾回收行为 //这里发生GC,obj1和obj2能否被回收? System.gc(); try { Thread.sleep(1000000); } catch (InterruptedException e) { e.printStackTrace(); } } }
④. 注意:Java使用的不是引用计数法(Java之所以没有使用引用计数法,是由于不能解决循环引用问题) | (Python使用了是引用计数法)
⑥. Python如何解决循环引用( 扩展了解 )
手动解决:很好理解,就是在合适的时机,解除引用关系
使用弱引用weakref,weakref是Python提供的标准库,旨在解决循环引用(只要发生了回收,弱引用都会被回收)
②. 枚举根节点做可达性分析
①. 基本思路是通过一系列名为"GC Roots"的对象(集合)作为起点,从这个被称为GC ROOTs 的对象开始向下搜索,如果一个对象到GC Roots没有任何引用链相连时,则说明此对象是不可达对象(被回收),否则就是可达对象
②. 在java中,可作为GC Roots的对象有
(1).虚拟机栈(栈帧中的局部变量表)中的引用对象(比如各个线程被调用的方法中使用到的参数、 局部变量等) (2).本地方法栈中JNI(即一般来说native方法)中引用的对象[ 线程中的start方法 ] (3).静态属性引用的对象(比如:Java类的引用类型静态变量) (4).方法区中常量引用的对象(比如:字符串常量池(String Table)里的引用) (5).所有被synchronized持有的对象 (6).Java虚拟机内部的引用(基本数据类型对应的Class对象,一些常驻的异常对象 [如NullPointerException、OutofMemoryError],系统类加载器) (7).反映java虚拟机内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存等 (8).注意:除了这些固定的GC Roots集合之外,根据用户所选用的垃圾收集器以及当前回收的内存区域 不同,还可以有其他对象临时加入,共同构架完成整GC Roots集合。比如:分代收集和局部回收(面试加分项)
③. 关于GCroot对象集合 注意事项:
注意:除了这些固定的GC Roots集合之外,根据用户所选用的垃圾收集器以及当前回收的内存区域不同,还可以有其他对象临时加入,共同构架完成整GC Roots 集合。比如: 分代收集和局部回收(面试加分项)
解释:如果只针对java堆中的某一区域进行垃圾回收(比如: 典型的只针对新生代),必须考虑到内存区域是虚拟机自己的实现细节,更不是孤立封闭的,这个区域的对象完全有可能被其他区域的对象所引用时候就需要一并将关联的区域对象也加入到GC Roots 集合中考虑,才能保证可达性分析的准确性
④. 小技巧:由于Root采用栈方式存放变量和指针,所以如果一个指针,它保存了堆内存里面的对象,但是自己又不存放在堆内存里面,那它就是一个Root
⑤. 优势:
相对于引用计数法而言,可达性分析算法不仅同样具备实现简单和执行高效 等特点,更重要的是该算法可以有效解决在引用计数算法中循环引用的问题,防止内存泄漏的发生
相较于引用计数算法,这里的可达性分析就是Java、C#选择的。这种类型的垃圾收集通常也叫做追踪性垃圾收集
⑥. 可达性分析算法的 注意事项:如果要使用可达性分析算法来判断内存是否可回收,
那么分析工作必须在 一个能保障一致性的快照中进行。这点不满足的话分析结果的准确
性就无法保证。这点也是导致GC进行时必须“StopTheWorld"的一个重要原因。
(即使是号称(几乎)不会发生停顿的CMS收集器中,枚举根节点时也是必须要停顿的)