图片加载<第四篇>:学会使用软引用解决OOM问题
学会使用软引用和弱引用可以进一步优化内存泄漏问题。
本文主要让大家了解什么叫强引用
、软引用
、弱引用
、虚引用
以及怎么使用。
(1)强引用(StrongReference)
Object object = new Object();
String name= "zhangsan";
强引用在项目中很常见,程序猿已经习惯性的使用强引用了,以上两句简单代码就是所谓的强引用。
当强引用对象占用的内存超过最大可分配内存时,就是发生OOM。
(2)软引用(SoftReference)
软引用是用来描述一些有用但并不是必需的对象,在Java中用java.lang.ref.SoftReference类来表示。对于软引用关联着的对象,只有在内存不足的时候JVM才会回收该对象。因此,这一点可以很好地用来解决OOM的问题,并且这个特性很适合用来实现缓存:比如网页缓存、图片缓存等。
SoftReference<String> str1 = new SoftReference<>(new String("hello1"));
Log.d("aaa", "str:"+str1.get());
//可以将软引用存入引用队列
ReferenceQueue<String> referenceQueue = new ReferenceQueue<>();
SoftReference<String> str2 = new SoftReference<>(new String("hello2"), referenceQueue);
Log.d("aaa", "str:"+str2.get());
(3)弱引用(WeakReference)
弱引用也是用来描述非必需对象的,当JVM进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象。在java中,用java.lang.ref.WeakReference类来表示。
WeakReference<String> str = new WeakReference<>(new String("hello"));
Log.d("aaa", "str:"+str.get());
System.gc();
Log.d("aaa", "str:"+str.get());
结果为:
图片.png(4)虚引用(PhantomReference)
虚引用和前面的软引用、弱引用不同,它并不影响对象的生命周期。在java中用java.lang.ref.PhantomReference类表示。如果一个对象与虚引用关联,则跟没有引用与之关联一样,在任何时候都可能被垃圾回收器回收。
要注意的是,虚引用必须和引用队列关联使用,当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会把这个虚引用加入到与之 关联的引用队列中。程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。
ReferenceQueue<String> queue = new ReferenceQueue<>();
PhantomReference<String> str = new PhantomReference<>(new String("hello"), queue);
Log.d("aaa", "str:"+str.get());
结果是:
图片.png(5)如何使用软引用解决OOM问题
BitmapFactory.decodeFile()
将图片转成bitmap,这句代码是非常消耗性能的,为了防止同一张图片频繁的转成bitmap,我们需要将bitmap存入缓存,代码如下:
private Map<String, Bitmap> bitmaps = new HashMap();
/**
* 将Bitmap保存到缓存
* @param path 文件路径
* @param bitmap 文件的bitmap对象
*/
private void addBitmapToCache(String path, Bitmap bitmap){
bitmaps.put(path, bitmap);
}
/**
* 获取缓存中的bitmap
* @param path
* @return
*/
private Bitmap getBitmap(String path){
Bitmap bitmap = bitmaps.get(path);
return bitmap;
}
这个想法不错,但是bitmap是非常占用内存的,如果缓存容器中存放多个bitmap对象很有可能造成OOM问题,解决OOM问题需要引用软引用
或者弱引用
,软引用
只有在内存不足的时候JVM才会回收该对象,弱引用
无论内存是否充足,JVM进行垃圾回收时,都会回收被关联的对象。这里采用软引用
较为适合。
private Map<String, SoftReference<Bitmap>> bitmaps = new HashMap();
/**
* 将Bitmap保存到缓存
* @param path 文件路径
* @param bitmap 文件的bitmap对象
*/
private void addBitmapToCache(String path, Bitmap bitmap){
bitmaps.put(path, new SoftReference<Bitmap>(bitmap));
}
/**
* 获取缓存中的bitmap
* @param path
* @return
*/
private Bitmap getBitmap(String path){
//获取软引用
SoftReference<Bitmap> softReference = bitmaps.get(path);
if(softReference == null){
return null;
}
Bitmap bitmap = softReference.get();
return bitmap;
}
以上代码是一个不错的方案,当获取的bitmap为null时,就重新在本地解码图片。