一、强引用
一个对象若持有强引用,垃圾回收器绝不会回收它。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。
特点:
- 强引用可以直接访问目标对象。
- 强引用所指向的对象在任何时候都不会被系统回收。JVM宁愿抛出OOM异常,也不会回收强引用所指向的对象。
- 强引用可能导致内存泄露。
java.lang.ref包中提供了几个类:SoftReference、WeakReference、PhantomReference,分别代表软引用、弱引用、虚引用。
ReferenceQueue类表示引用队列,它可以和这三种引用类联合使用,以便跟踪Java虚拟机回收所引用的对象的活动。
二、软引用(SoftReference)
软引用是除了强引用外,最强的引用类型。可以通过java.lang.ref.SoftReference使用软引用。
用法:
XXX xxx = new XXX();
SoftReference ref = new SoftReference(xxx);
XXX anotherXXX = (XXX)ref.get();
如果一个对象持有软引用,那么如果内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。
软引用可用来实现内存敏感的高速缓存。软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。ReferenceQueue中保存的对象是Reference对象,而且是已经失去了它所软引用的对象的Reference对象。
ReferenceQueue queue = new ReferenceQueue();
SoftReference ref = new SoftReference(xxx, queue);
利用ReferenceQueue.poll()方法,可以检查哪个SoftReference所软引用的对象已经被回收。于是可以把这些失去软引用的对象的SoftReference对象清除掉。常用的方式为:
SoftReference ref = null;
while ((ref = (EmployeeRef) q.poll()) != null) {
// 清除ref
}
示例
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher);
Drawable drawable = new BitmapDrawable(bitmap);
SoftReference<Drawable> drawableSoftReference = new SoftReference<Drawable>(drawable);
Drawable bgDrawable = drawableSoftReference.get();
if(bgDrawable!= null) {
view.setBackground(bgDrawable);
}
通过软引用的get()方法,取得drawable对象实例的强引用,发现对象被未回收。在GC在内存充足的情况下,不会回收软引用对象。
在实际中,会一起从网络请求多个图片,这时就会请求非常多的内存空间,导致内存吃紧,系统开始GC。GC后,drawables.get()不再返回Drawable对象,而是返回null,这时屏幕上背景图不显示,在系统内存紧张的情况下,软引用被回收。
使用软引用以后,在OutOfMemory异常发生之前,这些缓存的图片资源的内存空间可以被释放掉的,从而避免内存达到上限,避免Crash发生。
注意
在垃圾回收器对Java对象回收前,SoftReference类所提供的get方法会返回Java对象的强引用,一旦垃圾线程回收该Java对象之后,get方法将返回null。所以在获取软引用对象的代码中,一定要判断是否为null,以免出现NullPointerException导致应用崩溃。
三、弱引用(WeakReference)
用法:
WeakReference<XXX> sr = new WeakReference<XXX>(new XXX());
如果一个对象持有弱引用,那么在垃圾回收器线程扫描的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。
弱引用也可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。
弱引用与软引用的根本区别:
只具有弱引用的对象拥有更短暂的生命周期,可能随时被回收;
而只具有软引用的对象只有当内存不够的时候才被回收,在内存足够的时候,通常不被回收。
使用场景:
Handler中的使用,防止内存泄露。
软引用、弱引用都非常适合来保存那些可有可无的缓存数据。如果这样做,当系统内存不足时,这些缓存数据会被回收,不会导致内存溢出。而当内存资源充足时,这些缓存数据又可以存在相当长的时间。
如何选择软引用、弱引用?
- 如果只是想避免OutOfMemory异常的发生,则可以使用软引用。
- 如果对于应用的性能更在意,想尽快回收一些占用内存比较大的对象,则可以使用弱引用。
- 还可以根据对象是否经常使用来判断。如果该对象可能会经常使用的,就尽量用软引用;如果该对象不被使用的可能性更大些,就可以用弱引用。
- 另外,和弱引用功能类似的是WeakHashMap。WeakHashMap对于一个给定的键,其映射的存在并不阻止垃圾回收器对该键的回收,回收以后,其条目从映射中有效地移除。WeakHashMap使用ReferenceQueue实现的这种机制。
四、虚引用(PhantomReference)
虚引用是所有引用类型中最弱的一个。
一个持有虚引用的对象,和没有引用几乎是一样的,随时都可能被垃圾回收器回收。当试图通过虚引用的get()方法取得强引用时,总是会失败。并且,虚引用必须和引用队列一起使用,它的作用在于跟踪垃圾回收过程。
当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在垃圾回收后,销毁这个对象,将这个虚引用加入引用队列。