Java将对象引用分为4种类型,从而使程序更加灵活控制对象的生命周期,这四种类型从高到低依次为:强引用(Strong Reference),软引用(SoftReference),弱引用(WeakReference),虚引用(PhantomReference)。
强引用
强引用是我们在程序中最常见的引用,如代码String s = "abc"中变量s就是字符串对象"abc"的一个强引用。如果一个对象具有强引用,那么即使内存空间不足,垃圾回收器(GC)也不会回收它。
但是当给强引用对象置为null的话,那么该对象就可以被垃圾回收器回收。因为此时该对象不再含有其它强引用。
软引用
如果一个对象只具有软引用,那么内存空间足够时,GC不会回收它,但是当内存空间不足时,GC会回收它——故而可用来实现内存敏感的高速缓存。
软引用可使用java.lang.ref包下的SoftReference类来表示,如下:
Foo foo = new Foo();
SoftReference soft = new SoftReference(foo) ;
软引用和弱引用的区别在于,只具有弱引用的对象的生命周期更短暂。当垃圾回收线程扫描到它所管理的内存区域时,一旦发现了只具有弱引用的对象,不管当前内存空间是否足够都会回收对象的内存(不过,由于垃圾回收线程的优先级很低,因此不一定会很快发现)。
弱引用
如果一个对象只具有弱引用,那么当内存空间不足时,GC会回收对象所占用的内存空间。
弱引用使用java.lang.ref包下的WeakReference类来表示,如下:
WeakReference<Foo> weakCounter = new WeakReference<Foo>(foo); //weak reference
弱引用很适合用来存储元数据,比如,存储ClassLoader引用。如果没有类被加载,那么也就没有指向ClassLoader的引用,一旦上一次的强引用被丢弃,那么只具有弱引用的ClassLoader就会被回收。
另一个使用弱引用的例子是WeakHashMap。更多关于WeakHashMap 请点击
虚引用
虚引用并不会决定对象的生命周期,如果一个对象仅持有虚引用,那么它就和没有引用一样,在任何时候都可能被GC回收。虚引用主要要来跟踪对象被垃圾回收的活动。
虚引用和软引用/弱引用的一个区别是,虚引用必须和引用队列一起使用,程序可以通过引用队列中是否加入了虚引用来判断引用对象是否将要被回收。
PhantomReference phantom = new PhantomReference(foo);
ReferenceQueue
在构造软引用/弱引用时传入一个ReferenceQueue对象,当该引用指向的对象被标记为垃圾时,这个引用对象会自动地加入到引用队列中去,此后可在固定周期处理传入的引用队列,比如做一些清理工作来处理这些无效的引用对象。
在创建任何弱引用/软引用/虚引用的过程中,可通过如下代码提供引用队列:
ReferenceQueue refQueue = new ReferenceQueue();
Foo foo = new Foo();
PhantomReference<Foo> phantom = new PhantomReference<Foo>(foo, refQueue);
一个对象的生命周期可通过下图所述:
通常要避免使用引用对象,因为垃圾回收器需要特殊处理软引用,弱引用和虚引用。尽管引用对象在简化缓存的实现等方面很有作用,但大量的引用对象的存在会使得GC运行缓慢,且记录一个引用对象的开销远大于一个普通对象的开销。