JVM中对象的回收判定

JVM中是如何判断对象已经死亡

引用计数算法

给每个对象添加一个引用计数器,每当有一个地方引用该对象,计数器值加1;当引用失效时,计数器值就减1;任何时刻计数器为0的对象就是已经可以回收的对象。这种算法实现简单,判定效率也很高,在大部分情况下是一个不错的选择。但是当对象之间相互循环引用时,引用计数算法便无法在上面这种情况下通知GC收集器回收它们。

ReferenceCountingGC objA = new ReferenceCountingGC();
ReferenceCountingGC objB = new ReferenceCountingGC();

//objA和objB都通过instance字段获取对方的对象进行引用。
//因此它们的引用技术都不为0,GC收集器无法将它们回收
objA.instance = objB;
objB.instance = objA;

//objA和objB没有了任何引用对象
objA = null;
objB = null;
System.gc();

可达性分析算法

通过一系列“GC Roots”对象作为起始点,通过这些节点开始向下搜索,搜索所走过的路劲称为引用链,当一个对象到GC Roots没有任何引用链相连时(即从GC Roots到该对象不可达),则该对象可以被GC收集器回收。
JVM中能够长久存在的引用对象可作为GC Roots的对象,如:

  • 虚拟机栈(栈帧中的本地变量表)中引用的对象。
  • 方法区中类静态属性引用的遍历。
  • 方法区常量引用的对象。
  • 本地方法栈中Native方法引用的对象。

在这里插入图片描述 对象object1、object2、object3都可以通过引用链和GC Roots相连,因此这些对象无法被回收。而对象object4和object5随机互相关联,但是它们和GC Roots不可达,所以将会被判定为可回收的对象。

可达性分析算法中不可达的对象并不是一定会被回收,它们要在经历两次标记过程之后才能够确定:如果对象在进行可达性分析后发现没有与GC Roots相连的引用链,那么它将会被第一次标记并且进行筛选,筛选条件是对象是否有必要执行finalize()方法,如果当前对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机调用过了,则没有必要执行。反之,该对象会被放入一个F-Queue队列中,并由虚拟机开启一个线程触发该对象的finalize()方法,如果对象在finalize()方法中重新与引用链上的任何一个对象建立关联,那么在第二次标记时将会被移出“即将回收”的集合,否则将会被真正回收。

**注意:**没有对象的fianlize()方法最多只会被系统调用一次,因此每个对象都只有一次自救机会。

关于引用

对象是否存活与“引用”有着重要的关系。在JDK1.2以前,Java中的引用的定义很传统:如果reference类型的数据中存储的数值代表另一块内存的起始地址,则称这块内存代表着一个引用。
在JDK1.2以后,Java对引用的概念进行了扩充,将引用分为了强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Weak Reference),这四种引用强度由强到弱。1

  • 强引用:在程序中普遍存在,类似“Object obj = new
    Object()”这种引用,只要存在强引用,GC收集器就不会回收被引用对象。
  • 软引用:描述一些有用但是非必需的对象,在系统将要发生内存溢出异常之前,会将这些对象列进回收范围之中进行二次回收。如果此次回收还是没有足够内存,将会抛出内存溢出异常。通过SoftReference类实现软引用。
MyObject ref = new  MyObject();  
SoftReference softRef=new SoftReference(ref);  
//可以同 get()方法返回Java对象的强引用,如果Java对象被GC收集器回收,则返回null
MyObject anotherRef=(MyObject)aSoftRef.get(); 

-软引用可用来实现内存敏感的高速缓存,比如网页缓存、图片缓存等。使用软引用能防止内存泄露,增强程序的健壮性。

  • 弱引用:用来描述非必需对象,强度比软引用要弱,被弱引用关联的对象只能生存到下一次垃圾收集发生之前。当GC机制发生时,无论当前内存是否足够,都将回收只被弱引用关联的对象,如果存在强引用同时与之关联,则进行垃圾回收时也不会回收该对象(软引用也是如此)。通过WeakReference类实现。
WeakReference<String>reference=new WeakReference<String>(new String("aaa"));  
  • 虚引用:是最弱的一种引用关系。为一个对象设置虚引用关联的唯一目的就是能在这个对象被收集器回收之前收到一个通知。无法通过虚引用来获取一个对象实例。通过PhantomReference类实现。
    -虚引用必须和引用队列关联使用,当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会把这个虚引用加入到与之关联的引用队列中。程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。
ReferenceQueue<String> queue = new ReferenceQueue<String>(); 
PhantomReference<String> pr = new PhantomReference<String>(new String("hello"), queue);

  1. 深入理解Java虚拟机 ↩︎

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值