什么样的对象可以被回收
Java使用可达性分析的方法来判断某个对象是否应该被回收:
如图所示,就是通过一系列的称为”GC Roots”的对象作为起始点,从这些点向下搜索,搜索的路径称为引用链,当一个对象到达GC Roots没有任何引用链时,就可以证明这个对象是不可用的。那么这个对象就可以被回收了。像图中的Obj1-5都属于存活的对象,但是Obj6-8虽然还存在相互引用,但是已经是可以认为是死掉的对象了。
引用
目前来说,Java中的引用可以分为强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference)四种,他们的引用顺序依次逐渐减弱。
- 强引用是用来描述必须存在和引用的对象,比如Object a=new Object(),只要强引用还存在,被引用的对象就永远不会被回收。
- 软引用是用来描述一些还有用但是不是必需的对象。这类引用的对象会在内存溢出之前被列入回收范围进行第二次回收,如若回收完之后还没有获得足够的内存才会抛出内存溢出异常。可以使用SoftReference类来实现。
- 弱引用是用来描述非必需的对象,但是强度比软引用更弱,被引用的对象只能存活到下一次GC之前。当进行GC的时候不论内存是否足够都会对该引用的对象进行回收。可以使用WeakReference类来实现。
- 虚引用是最弱的引用关系。虚引用的存在不会对对象的存活造成任何影响,也不能通过虚引用来获得任何对象实例。设置虚引用的唯一目的就是在关联对象被回收时会获得一个系统通知。可以使用PhantomReference类来实现。
死亡对象的自我救赎
当一个对象在进行可达性分析的时候发现已经是没有任何引用的了,这时候垃圾收集器并没有立即判处该对象死刑,而是给了它一次自我救赎的机会,这时它会被标记一次,同时判断是不是有必要执行finalize()方法,当对象没有重写finalize()方法或者finalize()方法已经被执行过的时候,就不会执行finalize()方法:
- 执行finalize()方法:这时这个对象会被放在F-Queue队列之中,然后由虚拟机自动创建一个低优先级的Finalizer线程去执行它,但是为了保证F-Queue不被无限阻塞并不保证一定会等待它执行结束。此时在finalize()里如果对象又重新获得与GC Roots的联系就可以完成自我救赎,否则的话就只能被第二次标记,然后GG。
- 不执行finalize()方法:这时候要么是垃圾收集器已经给过一次机会了,要么是对象自己没有重写finalize()去获得机会,这个时候就只能被第二次标记,立即GG了。
方法区的回收
方法区的回收分为废弃常量的回收和无用类的卸载:
废弃常量的回收:回收废弃常量与上面所说的堆中对象的回收差不多,没有任何引用的时候回收。
无用类的卸载:类的卸载需要满足三个条件:
- 该类的所有对象都被回收
- 加载该类的ClassLoader已经被回收
- 该类对应的java.lang.Class没有在任何地方被引用,无法在任何地方通过反射访问该类
(但是满足这三个条件只是说可以被回收,但是不代表一定被回收,具体是否被回收还要由虚拟机里的一些参数来具体确定.)