Java堆中几乎存放着所有的实例对象,垃圾回收期进行回收之前,需要进行判断当前对象是否存活
(1) 引用计数算法
程序中创建的对象,会添加一个引用创建计数器,每当有一处引用,就会累加1,当引用失效时候就会减1。当计数器为0的时候就不在有任何引用
引用计算法实现起来比较简单,判断效率也很高,但是在主流的Java虚拟机中并未使用其来管理内存,主要原因其无法解决对象间互相循环引用的问题。
(2) 可达性分析算法
可达性分析是Java、C#中的主流算法,从“GC Roots”的对象作为起点,向下进行搜索,整个路径为引用链。当“GC Roots”到某个对象不可达时,这个对象就是不可用的。该对象就可以被回收
其中GC Roots的对象包含如下 :
1.虚拟机栈中引用的对象
2.方法区中类静态属性引用的对象
3.方法区中常量引用对象
4.本地方法栈中引用的对象
(3) 引用
JDK1.2后,Java对引用进行扩充,讲引用划分(强引用、软引用、若引用、虚引用)
强引用:必须对象,一个变量引用一个对象,只要是强引用垃圾回收器永远不会回收。
public static Useruser=new User();
软引用:有用但是非必须的对象,被软引用类型包裹的对象,person变量对User的引用就是软引用。在系统将要发生内存溢出时,就会将这些软引用进行回收,如果内存还不够就会产生内存溢出
public static Person<User> person=new Person<User>(new User());
弱引用:非必须的对象,比软引用更弱一些,被弱引用关联的对象,生命周期为下一次垃圾回收之前。当垃圾收集器工作时,无论空间是否充足,都会进行回收掉
虚引用:是最弱的一种引用。一个对象是否有虚引用的存在,完全不会对其生存时间产生影响。也无法通过虚引用来取得一个对象的实例。对象虚引用关联的唯一目的,就是在这个对象系统被垃圾器回收时,收到一个通知
(4) finalize()方法
当可达性分析算法发现某个对象不可达,那么会将次对象进行一次标记并且进行筛选(此对象是否需要执行finalize()方法)
当对象没有覆盖finalize()方法 或者 finalize()方法已经被虚拟机调用,这两种情况都不需要执行finalize()方法
如果该对象判断为有必要执行,那么会将该对象放置F-Queue队列中,会由虚拟机建立的优先级低的Finalizer线程去执行。如果一个对象在finalize()方法中执行非常缓慢,或者发生死循环,很可能导致F-Queue队列中其他对象处于永久等待,导致整个回收系统崩溃
经过finalize()方法标记之后,GC对F-Queue队列标记之前,如果对象与引用连建立关联,那么该对象就不会被回收,否则就会回收。
finalize()运行代价比较高,不确定性大(不一定回收),无法保证各对象间调用顺序,不建议使用次方法,建议使用try-finally或者其他