Java引用(reference)

Java引用(reference)

Java语言具备内存的回收机制。当某个对象不被引用时,内存回收机制将该对象销毁。但这种机制也导致了另一种问题,如果对某个对象的引用一直存在,该对象将无法被释放,即使内存不足的情况下。在某些情况,程序对某个对象是否被释放不是很重要的情况,为了保证系统的运行,释放这一类的对象,是很有必要的。Java为了解决这个问题,引入了java.lang.ref包,称为弱引用的类(相对通常的强引用而言)。

java.lang.ref包内类的对象可以指向其他对象,并且这些引用的存在不影响垃圾回收器对指向对象的回收。其好处是使用者可以保持对使用对象的引用,同时JVM还可以在内存不够时对指向的对象进行回收,因而这个包适合用来实现与缓存相关的应用,同时该包的类还提供在对象的“可达性”发生变化时,进行提醒的机制。

图1 java.lang.ref包的结构

 

图2 java.lang.ref包类的继承关系

 

Reference 是一个抽象类,SoftReference,WeakReference,PhantomReference 以及 FinalReference 都是继承它的具体实现类。

 

 

StrongReference

 

Java语言中对象都是在堆heap上分配,当对象不被引用时将被内存回收机制释放回heap中重用。通常所说的引用都叫强引用。例如string tag = new String(“Tag”); tag引用就为强引用,它具有以下特性:

可以直接访问目标对象

所指向的对象在任何时候都不会被系统回收

可能导致内存泄漏

 

相对于强引用来说,java.lang.ref包内的其它引用被称为“弱引用”。它们在某些条件下能被系统回收。

 

 

SoftReference

 

在这些“弱引用”中它最强,SoftReference所指向的对象,当没有强引用指向它时,会在内存中停留一段的时间,垃圾回收器会根据 JVM 内存的使用情况(内存的紧缺程度)以及 SoftReference 的 get() 方法的调用情况来决定是否对其进行回收。

 

SoftReference<Bean> bean = new SoftReference<Bean>(new Bean(“name”, 10));

System.out.println(bean.get());// “name:10”

 

软引用有以下特征:

使用 get() 方法取得对象的强引用从而访问目标对象。

所指向的对象按照 JVM 的使用情况(Heap 内存是否临近阈值)来决定是否回收。

可以避免 Heap 内存不足所导致的异常。

 

当垃圾回收器决定对其回收时,会先清空它的 SoftReference,此后所有SoftReference 的 get() 方法都将会返回 null,然后再调用对象的 finalize() 方法,并在下一轮 GC 中对其真正进行回收。

 

 

WeakReference

 

WeakReference是弱于SoftReference的引用类型。弱引用的特性和基本与软引用相似,区别就在于弱引用所指向的对象只要进行系统垃圾回收,不管内存使用情况如何,永远对其进行回收(get() 方法返回 null)。完全可以通过和 SoftReference 一样的方式来操作 WeakReference。

 

弱引用有以下特征:

使用 get() 方法取得对象的强引用从而访问目标对象。

一旦系统内存回收,无论内存是否紧张,弱引用指向的对象都会被回收。

也可以避免 Heap 内存不足所导致的异常。

 

PhantomReference

 

PhantomReference 是所有“弱引用”中最弱的引用类型。不同于软引用和弱引用,虚引用无法通过 get() 方法来取得目标对象的强引用从而使用目标对象,get() 被重写为永远返回 null。

虚引用主要被用来跟踪对象被垃圾回收的状态,通过查看引用队列中是否包含对象所对应的虚引用来判断它是否 即将被垃圾回收,从而采取行动。它并不被期待用来取得目标对象的引用,而目标对象被回收前,它的引用会被放入一个ReferenceQueue对象中,从而达到跟踪对象垃圾回收的作用。

所以具体用法和之前两个有所不同,它必须传入一个ReferenceQueue对象。当虚引用所引用对象被垃圾回收后,虚引用会被添加到这个队列中。

 

例如:

public static void main(String[] args) {

ReferenceQueue<String> refQueue = new ReferenceQueue<String>();

PhantomReference<String> referent = new PhantomReference<String>(

new String(“T”), refQueue);

System.out.println(referent.get());// null

 

System.gc();

System.runFinalization();

 

System.out.println(refQueue.poll() == referent); //true

}

 

对于引用回收方面,虚引用类似强引用不会自动根据内存情况自动对目标对象回收,Client 需要自己对其进行处理以防Heap内存不足异常。

 

虚引用有以下特征:

永远无法使用get()方法取得对象的强引用从而访问目标对象。

所指向的对象在被系统内存回收前,虚引用自身会被放入ReferenceQueue对象中从而跟踪对象垃圾回收。

不会根据内存情况自动回收目标对象。

 

另外值得注意的是,其实 SoftReference, WeakReference 以及 PhantomReference 的构造函数都可以接收一个 ReferenceQueue 对象。当 SoftReference 以及 WeakReference 被清空的同时,也就是 Java 垃圾回收器准备对它们所指向的对象进行回收时,调用对象的 finalize() 方法之前,它们自身会被加入到这个 ReferenceQueue 对象中,此时可以通过 ReferenceQueue 的 poll() 方法取到它们。而 PhantomReference 只有当 Java 垃圾回收器对其所指向的对象真正进行回收时,会将其加入到这个 ReferenceQueue 对象中,这样就可以追综对象的销毁情况。

 

 

FinalReference 以及 Finzlizer

 

FinalReference是java.lang.ref 里的一个不能被公开访问的类。FinalReference代表的正是 Java中的强引用。Bean bean = new Bean();在虚拟机的实现过程中,实际采用了 FinalReference类对其进行引用。而Finalizer,除了作为一个实现类外,更是在虚拟机中实现一个 FinalizerThread,以使虚拟机能够在所有的强引用被解除后实现内存清理。

首先,通过声明 FinalizerThread,并将该线程实例化,设置为守护线程后,加入系统线程中去。

 

static {

ThreadGroup tg = Thread.currentThread().getThreadGroup();

for (ThreadGroup tgn = tg;

tgn != null;

tg = tgn, tgn = tg.getParent());

 

Thread finalizer = new FinalizerThread(tg);

finalizer.setPriority(Thread.MAX_PRIORITY – 2);

finalizer.setDaemon(true);

finalizer.start();

}

 

在GC的过程中,当一个强引用被释放,由系统垃圾收集器标记后的对象,会被加入 Finalizer对象中的ReferenceQueue中去,并调用Finalizer.runFinalizer()来执行对象的finalize 方法。

 

private void runFinalizer() {

synchronized (this) {

if (hasBeenFinalized()) return;

remove();

}

 

try {

Object finalizee = this.get();

if (finalizee != null && !(finalizee instanceof java.lang.Enum)) {

invokeFinalizeMethod(finalizee);

/* 注意,这里需要清空栈中包含该变量的的slot,

** 从而来减少因为一个保守的GC实现所造成的变量未被回收的假象 */

finalizee = null;

}

} catch (Throwable x) { }

super.clear();

}

 

注意,标记处所调用的invokeFinalizeMethod为native 方法,由于 finalize 方法在 Object 类中被声明为 protected,这里必须采用 native 方法才能调用。随后通过将本地强引用设置为空,以便使垃圾回收器清理内存。

通过这样的方法,Java 将四种引用对象类型:软引用 (SoftReference),弱引用 (WeakReference),强引用 (FinalReference),虚引用 (PhantomReference) 平等地对待,并在垃圾回收器中进行统一调度和管理。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值