android 弱引用 软引用,内存不够用导致OOM?软引用和弱引用来助你一臂之力

Android历经10余年的迭代,在内存方面取得了很大的进步,但是如何进行内存优化,让应用占用更小的内存,一直都是开发者需要思考的事情。本篇文章主要介绍利用软引用和弱引用,达到内存优化的目的,降低OOM的发生概率。

软引用和弱引用的特点

软引用:新建的对象为软引用,当内存不够时,回收器就会回收这些对象,如果回收后还是没有足够的内存,抛出OutOfMemoryError异常;

弱引用:新建对象为弱引用时,垃圾回收器不管当前内存是否足够,都会回收它的内存;

软引用的使用

简单使用

代码如下:

MyObject object = new MyObject();//创建一个对象

SoftReference softRef = new SoftReference( object );//创建对象的软引用

if(softRef != null){

MyObject anotherRef =(MyObject) aSoftRef .get();//通过软引用获取对象

}

复制代码

SoftReference 它的一个实例保存着一个 object 对象的软引用,在 object 对象回收之前, SoftReference 类所提供的 get() 方法都会返回 这个object 对象的强引用,一旦回收该 Java 对象之后, get() 方法将返回 null 。所以在获取软引用对象的代码中,一定要判断是否为null,以免出现NullPointerException异常导致应用崩溃。

结合ReferenceQueue使用

代码如下

MyObject object = new MyObject();//创建一个对象

ReferenceQueue queue = new ReferenceQueue();//创建引用队列

SoftReference softRef = new SoftReference( object, queue );// 把引用加入到引用队列

复制代码

SoftReference 也是一个Java对象,具有Java对象的一般特性,当它保存的对象的软引用被回收时,它也就失去了存在的意义,这时就需要一个适当的清除机制,避免大量 SoftReference 对象带来的内存泄漏,ReferenceQueue就可以解决这个问题。当这个 SoftReference 所软引用的 object 被垃圾收集器回收的同时,softRef 所强引用的 SoftReference 对象被列入 ReferenceQueue 。调用ReferenceQueue的 poll() 方法,如果这个队列中不是空队列,那么将返回队列前面的那个 Reference 对象。

利用这个方法,可以检查哪个 SoftReference 所软引用的对象已经被回收。可以把这些失去 软引用的对象的 SoftReference 对象清除掉,代码如下:

SoftReference ref = null ;

while ((ref = (EmployeeRef) q .poll()) != null ) {

// 清除 ref

}

复制代码

如何利用软引用达到内存合理利用

软引用的生命周期可以是很长的,只要内存足够,就不会被回收, 可以用来实现内存敏感的高速缓存,比如说处理图片这种占用内存大的类。假设在我们的需求中,需要很多的默认图片,比如头像,游戏图标这些,读取图片需要从硬盘读取,这样影响性能,全部加载到内存中,则会有可能导致内存吃紧而发生OOM,在这个时候使用软引用就能很好的解决问题。

private Map> imageCache = new HashMap>();


....

public void addBitmapToCache(String path) {

// 强引用的Bitmap对象

Bitmap bitmap = BitmapFactory.decodeFile(path);

// 软引用的Bitmap对象

SoftReference softBitmap = new SoftReference(bitmap);

// 添加该对象到Map中使其缓存

imageCache.put(path, softBitmap);

}

public Bitmap getBitmapByPath(String path) {

// 从缓存中取软引用的Bitmap对象

SoftReference softBitmap = imageCache.get(path);

// 判断是否存在软引用

if (softBitmap == null) {

return null;

}

// 取出Bitmap对象,如果由于内存不足Bitmap被回收,将取得空

Bitmap bitmap = softBitmap.get();

return bitmap;

}

复制代码

内存不足时,JVM自动回收缓存图片对象所占用的空间,避免了OOM的问题。

弱引用的使用

简单使用

WeakReference wef = new WeakReference(new User());

if(wef.get() != null){

User anotherRef =(MyObject) wef .get();//通过软引用获取对象

}

复制代码

假如在wef.get();执行之前,执行了GC,那么获得的值为null,弱引用是不管内存是否充足,都是会被回收的。

结合ReferenceQueue使用

ReferenceQueue queue = new ReferenceQueue()

WeakReference wef = new WeakReference(new User(),queue);

复制代码

弱引用和软引用的使用方法类似,就不重复说了。弱引用也可以用来保存那些可有可无的数据,还被经常用来解决有可能产生的内存泄漏问题。

如何利用弱引用避免有可能产生的内存泄漏问题

利用弱引用避免产生内存泄漏的例子有很多,最长见的有Handler的内存泄漏问题。

代码如下

public class MainActivity extends AppCompatActivity {

private Handler handler ;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

handler = new MyHandler( this ) ;

new Thread(new Runnable() {

@Override

public void run() {

handler.sendEmptyMessage( 0 ) ;

}

}).start() ;

}

private static class MyHandler extends Handler {

WeakReference weakReference ;

public MyHandler(MainActivity activity ){

weakReference = new WeakReference( activity) ;

}

@Override

public void handleMessage(Message msg) {

super.handleMessage(msg);

if ( weakReference.get() != null ){

// update android ui

}

}

}

}

复制代码

内部实例会持有外部类引用,所以如果当Activity已经销毁,但是还有消息没处理完毕,那么MyHandler还持有actiivty的引用,这样就会造成内存泄漏。声明一个静态的Handler内部类,并持有外部类的弱引用 ,这样就能很好的防止内存泄漏。

弱引用还会用在内存缓存中,比如我们经常用到的Glide加载图片框架,源码里对图片的处理也用到了软引用技术,感兴趣的可以去探究Glide的缓存策略(没有能力讲明白,在这里就不敢吭声了),源码关键代码如下:

public LoadStatus load(Key signature, int width, int height, DataFetcher fetcher,

DataLoadProvider loadProvider, Transformation transformation, ResourceTranscoder transcoder,

Priority priority, boolean isMemoryCacheable, DiskCacheStrategy diskCacheStrategy, ResourceCallback cb) {

Util.assertMainThread();

long startTime = LogTime.getLogTime();

final String id = fetcher.getId();

EngineKey key = keyFactory.buildKey(id, signature, width, height, loadProvider.getCacheDecoder(),

loadProvider.getSourceDecoder(), transformation, loadProvider.getEncoder(),

transcoder, loadProvider.getSourceEncoder());

//使用LruCache获取缓存

EngineResource> cached = loadFromCache(key, isMemoryCacheable);

if (cached != null) {

//从缓存中获取资源成功

cb.onResourceReady(cached);

if (Log.isLoggable(TAG, Log.VERBOSE)) {

logWithTimeAndKey("Loaded resource from cache", startTime, key);

}

return null;

}

//从弱引用中获取缓存

EngineResource> active = loadFromActiveResources(key, isMemoryCacheable);

if (active != null) {

//从缓存中获取资源成功

cb.onResourceReady(active);

if (Log.isLoggable(TAG, Log.VERBOSE)) {

logWithTimeAndKey("Loaded resource from active resources", startTime, key);

}

return null;

}

//开启线程从网络中加载图片......

EngineJob current = jobs.get(key);

if (current != null) {

current.addCallback(cb);

if (Log.isLoggable(TAG, Log.VERBOSE)) {

logWithTimeAndKey("Added to existing load", startTime, key);

}

return new LoadStatus(cb, current);

}

......

}

复制代码

无论是弱引用还是软引用,都可以用来存储可有可无的数据,声明一些生命周期比较长的对象,至于用哪一个,需要视情况而定。

总结

个人认为,想避免OutOfMemory异常的发生,可以考虑使用软引用。从性能上面去考虑,如果对一些占用内存比较大的对象使用弱引用,就能更及时的被回收。软引用被回收的概率要比弱引用更低,经常要使用的对象,使用软引用更好。对应用进行内存优化是很重要的,软引用和弱引用技术都能让使用内存更合理化,但是要视情况而定,不能滥用。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值