Java垃圾回收--对象回收判定(可达性分析算法&对象引用)

1 述

  • 对象的回收判定通常有两种算法 : 引用计数算法和可达性分析算法。
  • 判定对象是否存活(需要回收)都与“引用”有关。

2 引用计数算法

  • 给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;
  • 当引用失效时,计数器值就减1;
  • 任何时刻计数器为0的对象就是不可能再被使用的,这时候变可通知GC收集器回收这些对象。
  • Java虚拟机里面没有选用引用计数算法来管理内存,其中最主要的原因是它很难解决对象之间相互循环引用的问题
  • 优点:简单,高效,现在的objective-c用的就是这种算法。 缺点:很难处理循环引用,相互引用的两个对象则无法释放。(需要开发者自己处理)
ClassA a=new ClassA();
ClassB b=new ClassB();
a.setMethod(b);
b.setMethod(a);

3 可达性分析算法

  • Java虚拟机中,是通过可达性分析(Reachability Analysis)来判定对象是否存活的。
  • 这个算法的基本思路是通过一系列称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链项链时,则证明此对象是不可用的
160f7b667b1af119.png

GC Roots的对象
1.虚拟机栈(栈帧中的局部变量表)中的引用对象
2.方法区中类静态属性(静态对象)引用的对象
3.方法区中常量(final 修饰的成员对象)引用的对象。
4.本地方法栈中JNI(Native)引用的对象。

PS : 成员对象(即存储在堆)的引用的对象为何不在GC Roots?

4 对象之引用

引用分为强引用(Strong Reference)软引用(Soft Reference)弱引用(Weak Reference)虚引用(Phantom Refernce)

  • 强引用 : 类似Object obj=new Object()这类的引用,只要强引用还在,垃圾收集器永远不会回收掉被引用的对象
  • 软引用 : 软引用是用来描述一些有用但非必须的对象,在系统将要发生内存溢出(OOM)异常之前,将会把这些对象列进回收范围之中进行二次回收。如果这次回收还没有足够的内存,才会抛出内存溢出(OOM)异常。JDK1.2之后提供了SoftReference类来实现软引用。
  • 软引用主要用来实现类似缓存的功能,在内存足够的情况下直接通过软引用取值,无需从繁忙的真实来源获取数据,提升速度;当内存不足时,自动删除这部分缓存数据,从真正的来源获取这些数据。
Object obj = new Object();
SoftReference sf = new SoftReference(obj);
 
 
  • 弱引用 : 弱引用也是用来描述非必需对象的,但是它的引用比软引用更弱一些,被弱引用关联的对象只能生存到下一次垃圾收集发生之前,当垃圾收集器工作时,无论当前内存是否足够,都会被回收。JDK1.2之后提供了SoftReference类来实现软引用。
Object obj = new Object();
WeakReference wf = new WeakReference(obj);
 
 
  • 虚引用 : 虚引用也成为幽灵引用或者幻影引用,它是最弱的一种引用关系。无法通过虚引用来取得一个对象的实例。为一个对象设置虚引用的唯一目的就是能够在这个对象被回收的时候收到一个系统通知
Object obj = new Object();
PhantomReference pf = new PhantomReference(obj);
 
 

5 方法区的回收

  • 因为方法区主要存放永久代对象,而永久代对象的回收率比新生代差很多,因此在方法区上进行回收性价比不高。
  • 主要是对常量池的回收和对类的卸载。
  • 类的卸载条件很多,需要满足以下三个条件,并且满足了也不一定会被卸载:
  • 该类所有的实例都已经被回收,也就是 Java 堆中不存在该类的任何实例。
  • 加载该类的 ClassLoader 已经被回收。
  • 该类对应的 java.lang.Class 对象没有在任何地方被引用,也就无法在任何地方通过反射访问该类方法。
  • 可以通过 -Xnoclassgc 参数来控制是否对类进行卸载。
  • 在大量使用反射、动态代理、CGLib 等 ByteCode 框架、动态生成 JSP 以及 OSGo 这类频繁自定义 ClassLoader 的场景都需要虚拟机具备类卸载功能,以保证不会出现内存溢出。

6 finalize()

  • finalize() 类似 C++ 的析构函数,用来做关闭外部资源等工作。
  • 但是 try-finally 等方式可以做的更好,并且该方法运行代价高昂,不确定性大,无法保证各个对象的调用顺序,因此最好不要使用。
  • 当一个对象可被回收时,如果需要执行该对象的 finalize() 方法,那么就有可能通过在该方法中让对象重新被引用,从而实现自救。

你可能感兴趣的:(Java垃圾回收--对象回收判定(可达性分析算法&对象引用))