一、GC需要做的三件事
哪些内存需要回收?
什么时候回收?
怎么回收?
二、判断对象是否“已死”
“已死”对象:不会再通过任何途径被使用
1、引用计数算法
在对象中添加一个计数器,当被引用时加1,当引用失效时减1;计数器为0时就是不可能在被使用的
优点:实现简单、判定效率高
缺陷:无法解决对象间互相引用问题
使用:微软COM技术、使用ActionScript3的FlashPlayer、Python
2、根搜索算法
已一系列名为“GC roots”的对象为起点向下搜索,搜索走过的路径叫做引用链;当一个对象到GC Roots对象没有任何引用链(对象不可达),则认为此对象不可用。
上图中Object 5、6、7到GC Roots中无引用链,因此判定“已死”,然后进行回收
在java中,可以当做GC Roots对象的有:
- 虚拟机栈(栈帧中的本地变量表)中的引用的对象
- 方法区中类静态属性引用的对象
- 方法区中的常量引用的对象
- 本地方法栈中JNI(Native方法)的引用的对象
3、引用
在JDK1.2之前:如果reference类型的数据中存储的数值代表另一块内存的起始地址,就称这块内存代表着一个引用
在JDK1.2之后进行了补充:将引用分为强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference),引用强度依次降低
- 强引用:就是指代码中普遍存在的类似“Object obj = new Object();” 这类的引用,只要强引用存在,垃圾收集器永远不会回收被引用的对象
- 软引用:用来描述一些还有用,但并非必须的对象。对于软引用关联着的对象,在系统将要发生内存溢出之前,会对此类引用进行第二次回收
- 弱引用:用来描述非必须对象,当垃圾收集器工作时,无论内存是否够用,被引用的对象都会被回收掉
- 虚引用:也称幽灵引用、幻影引用,最弱的一种引用关系。一个虚引用的存在,不会对其生存时间构成影响,也无法通过虚引用获得一个对象实例;为对象设立虚引用关联的唯一目的是就是在垃圾收集器进行收集时收到一个系统通知
4、生存还是“死亡”
在根搜索算法中不可达的对象,还不能最终确定“已死”状态。
真正确定对象已死,还需要至少经历两次标记过程:
1)、在根搜索算法中没有引用链,被标记一次并经历一次筛选,筛选的条件是此对象是否有必要执行finalize()方法;判断是否有必要执行finalize()方法有两个条件:已经执行过finalize()方法、对象没有覆盖finalize()方法则认为没必要执行
如果判断有必要执行finalize()方法,则把对象放入F-Queue队列中,并由稍后由虚拟机自动创建的低优先级的Finalizer线程去执行。
2)、稍后GC会对F-Queue中的对象进行第二次标记,如果对象要在finalize中拯救自己,只需要与引用链上的对象建立一个关联即可,并且会在第二次标记时被移出“即将回收”的集合,否则就嗝屁了。