2.垃圾收集器
如何判断对象需要回收?
-
引用计数算法: 给对象中添加一个引用计数器, 每当有一个地方引用它时, 计数器值就加1; 当引用失效时, 计数器值就减1; 任何时刻计数器为0的对象就是不可能再被使用的。
难以解决循环引用问题!(给个例子)
A.instance=B; B.instance=A; A=null; B=null;
-
可达性分析算法(Java,C#): 当一个对象到GC Roots没有任何引用链相连时, 则证明此对象是不可用的。
可以作为GCRoot的对象:
- 虚拟机栈或本地方法栈中引用的对象;
- 方法区中类静态属性或常量引用的对象。
3.强引用,软引用,弱引用和虚引用
-
强引用:不会被回收,Object obj = new Object();
-
软引用:有用但并非必须,在即将OOM时会被回收,Java提供SoftReference类实现软引用;
-
弱引用:只能存活到下一次垃圾回收之前,WeakReference类实现;
什么是WeakHashMap
-
虚引用:无法通过虚引用取得一个对象实例,唯一作用在于虚引用关联的对象在被垃圾回收时会受到一个系统通知,PhantomReference类实现。
4.确定需要被回收的对象
不可达的对象都会被回收吗
一个对象的死亡至少经历两次标记的过程:
- 可达性分析发现没有与GCRoot连接的引用,则会被第一次标记并进行一次筛选,筛选的条件时是否有必要执行finalize()方法。若对象没有覆盖finalize()方法或finalize() 方法已经被虚拟机调用过,则他们都被认为“没有必要执行”;
- 对象被判定有必要执行finalize()后,会被放入F-Queue队列。GC会对F-Queue中的对象第二次标记,若对象在finalize()中重新被引用(如通过this被赋值),则会被移除处队列中。
- finalize()只能被调用一次
- finalize()不是析构函数,不建议使用(推荐try…finally…)
5.回收方法区
方法区会发生垃圾回收吗
Java虚拟机规范中不要求虚拟机回收方法区。
方法区的回收包括:废弃常量和无用的类
- 判断废弃常量也是可达性分析
- 判断无用的类:
- 该类所有实例被回收
- 加载该类的ClassLoader被回收
- 该类对应的java.lang.Class对象没有被引用,无法通过反射访问该类的方法
对与大量使用反射、动态代理的框架,频繁自定义ClassLoader的场景都需要虚拟机具备类卸载功能,保证方法区不会溢出。