java 软引用、弱引用、强引用、虚引用的解析
来源:互联网 发布:世界粮农组织数据库 编辑:程序博客网 时间:2024/05/18 04:01
写了那么多篇文章第一次使用MarkDown编辑器。。。
- 软引用与强引用、弱引用、虚引用的对比
软引用、强引用、弱引用、虚引用
- 强引用
- 弱引用
- 虚引用
- 软引用
强引用
强引用也就是我们一般使用的引用,如若一个对象有强引用,那么即使内存不足的情况出现,强引用对象也不会被轻易的回收
String s = new String();
创建了一个String对象,并用一个变量s存储对这个对象的引用。这就是个强引用。
变量持有的是这个对象的引用。通常,引用是一个对象的存储地址(但不同于c++、c,这个引用不能转换成整数)。而强引用其实就是正在使用的对象
虚引用
虚引用其实没什么用,和弱引用一样不会介入引用对象的生命周期。它的get方法总是返回null,所以你得不到它引用的对象。它的唯一作用就是跟踪对象合适被回收,但是必须要和引用队列 (ReferenceQueue)联合使用。当垃圾回收机制准备回收一个对象的时候,如果发现这个对象还存在一个虚引用,就会在这个对象被回收之前将这个虚引用加入到引用队列中,如果在引用队列中发现虚引用,那么就说明与之关联的对象将要被回收了。
弱引用
如果一个对象持有的是弱引用,垃圾回收机制是会去回收这个对象的,但是垃圾回收是优先级很低的线程,所以不一定很快能被回收。这个会在什么情况应用呢?看过android官网图片加载demo的同学们应该就比较能理解,我这里就直接拿过来用,作为弱引用的讲解例子。
class BitmapWorkerTask extends AsyncTask { private final WeakReference imageViewReference; private int data = 0; public BitmapWorkerTask(ImageView imageView) { // Use a WeakReference to ensure the ImageView can be garbage collected imageViewReference = new WeakReference(imageView); } // Decode image in background. @Override protected Bitmap doInBackground(Integer... params) { data = params[0]; return decodeSampledBitmapFromResource(getResources(), data, 100, 100)); } // Once complete, see if ImageView is still around and set bitmap. @Override protected void onPostExecute(Bitmap bitmap) { if (imageViewReference != null && bitmap != null) { final ImageView imageView = imageViewReference.get(); if (imageView != null) { imageView.setImageBitmap(bitmap); } } }}
这里就有一个imageview的弱引用,AsyncTask 这个大家都应该不陌生就不再介绍,这里在这个异步加载线程中加载图片,然后显示到imageview上面。而imageview是在ui线程(也就是主线程),我们不能保证用户什么时候会结束这个主线程,而此时已经启动了这个图片异步加载线程,我们不知道它什么时候会加载完,如果线程拥有的是imageview的强引用的话,这个imageview在用户退出的时候就不能被回收,也就会造成内存泄露的情况,在使用handler的时候也经常会遇到这个问题,就是你在activity中启动一个线程,使用handler处理信息,如果activity退出,而线程是不会退出的,还会持有handler对象,也就造成了handler不能被回收,内存泄露就出现了。而弱引用就解决了这个问题,像上面的代码,ui线程结束imageview此时要回收,因为图片加载线程中持有的是imageview的弱引用,他不会影响他所弱引用对象的回收,也就不会造成内存泄露,而此时如果弱引用的对象已经被回收,imageViewReference.get();得到的就是空
软引用
软引用在内存优化、速度优化中是经常会被用到的,软引用可用来实现内存敏感的高速缓存。如果一个对象有一个软引用,那么只要内存空间足够,他就不会被回收,我们就可以使用这些对象,相当于回收利用吧。我们知道开辟内存的消耗还是比较大的(不管是事件还是空间上),所以复用就可以做到减少内存的消耗,速度优化等。可以和引用队列联合使用。
这里要再次说下android官网的图片加载demo,还是建议大家去看看。
http://developer.android.com/intl/zh-cn/training/displaying-bitmaps/index.html
这里又要用到这里面的例子程序来讲软引用,但是他的demo中没有结合引用队列使用,下面就结合demo介绍:
首先来说说他的应用场景:异步加载大量的图片,大量图片的话就必定会用到内存缓存以提高速度。使用的是LruCache来缓存图片,也就是结合了最近最久未使用算法的缓存,这个缓存要有大小限制的(要是把全部内存都占了那肯定不行),也就是会有图片从这个缓存中移除,这个时候就用到了软引用,将那些所有被移出缓存的图片(bitmap对象)绑定软引用,加入到一个容器中存储,然后等到需要新的bitmap对象的时候就从这个容器中循环拿可以使用的进行复用(创建新的bitmap内存很耗时,也很费内存,复用大大提高效率)。
下面就是被移除的对象添加软引用的代码
mMemoryCache = new LruCache<String, BitmapDrawable>(mCacheParams.memCacheSize) { // Notify the removed entry that is no longer being cached. @Override protected void entryRemoved(boolean evicted, String key, BitmapDrawable oldValue, BitmapDrawable newValue) { if (RecyclingBitmapDrawable.class.isInstance(oldValue)) { // The removed entry is a recycling drawable, so notify it // that it has been removed from the memory cache. ((RecyclingBitmapDrawable) oldValue).setIsCached(false); } else { // The removed entry is a standard BitmapDrawable. if (Utils.hasHoneycomb()) { // We're running on Honeycomb or later, so add the bitmap // to a SoftReference set for possible use with inBitmap later. mReusableBitmaps.add (new SoftReference<Bitmap>(oldValue.getBitmap())); } } }....
循环找可以复用的bitmap
protected Bitmap getBitmapFromReusableSet(BitmapFactory.Options options) { Bitmap bitmap = null; if (mReusableBitmaps != null && !mReusableBitmaps.isEmpty()) { synchronized (mReusableBitmaps) { final Iterator<SoftReference<Bitmap>> iterator = mReusableBitmaps.iterator(); Bitmap item; while (iterator.hasNext()) { item = iterator.next().get(); if (null != item && item.isMutable()) { // Check to see it the item can be used for inBitmap. if (canUseForInBitmap(item, options)) { bitmap = item; // Remove from reusable set so it can't be used again. iterator.remove(); break; } } else { // Remove from the set if the reference has been cleared. iterator.remove(); } } } } return bitmap;}
上面我们说了要结合引用队列使用,但是上面的而梨子中其实没有用到。先说说引用队列的用处吧:
String s = new String();ReferenceQueue queue = new ReferenceQueue();SoftReference ref=new SoftReference(s, queue);
如上述代码 ,一开始s是强引用,然后创建了一个引用队列,以及结合了引用队列的软引用,此时如果s=null;(上面也讲到了,垃圾回收是一个优先级很低的线程,所以不会那么快回收),但这里假设s被回收了,那么ref就会加入到queue中,此时ref通过get方法得到的结果已经是null了,我们可以利用这个来清除没有用的软引用,如果像上面这样是单个的软引用对象的话就可以不用,但是很多时候我们会有一堆软引用然后都放在容器中,这个时候就需要去清理其中没有用的软引用,因为如果那个存软引用的容器存了一堆没用的,也是很大的消耗。
引用队列的使用以及为什么要使用也说了,为什么上面android官网的加载图片的demo中没有用到引用队列大家结合一下代码看看就知道了,引用队列就一个用处:清理没用的软引用,而上面的demo中我们可以看到他循环读取其中的软引用,判断是否为空(也就是没用了的软引用)等条件,不符合就直接移除了,也就做了清理没用的软引用的工作。
讲完了。。。最后要说,软引用、弱引用真的是比较好用的,一定要学会灵活使用。
- Java的强引用、软引用、弱引用、虚引用
- java的强引用,软引用,弱引用,虚引用
- java的强引用、软引用、弱引用、虚引用
- java 软引用、弱引用、强引用、虚引用的解析
- Java中强引用、软引用、弱引用、虚引用内容解析------夜空中最亮的星
- Java 强引用、 软引用、 弱引用、虚引用
- Java 强引用、 软引用、 弱引用、虚引用
- Java 强引用、 软引用、 弱引用、虚引用
- Java 强引用、 软引用、 弱引用、虚引用
- Java 强引用、 软引用、 弱引用、虚引用
- Java 强引用、 软引用、 弱引用、虚引用
- java 强引用,软引用,弱引用,虚引用
- java 强引用,软引用,弱引用,虚引用
- Java 强引用、软引用、弱引用、虚引用
- Java 强引用、 软引用、 弱引用、虚引用
- Java 强引用、 软引用、 弱引用、虚引用
- Java强引用、 软引用、 弱引用、虚引用
- Java 强引用、 软引用、 弱引用、虚引用
- Android实现获取验证码的倒计时功能
- 基数排序的数组/链表实现
- eclipse编码格式设置教程、如何为eclipse设置编码格式?
- Android-Universal-Image-Loader 图片异步加载类库的使用(超详细配置)
- ng1.3+表单验证<AngularJs>
- java 软引用、弱引用、强引用、虚引用的解析
- C++实验2—学生成绩
- checkio the most frequent weekdays
- IOS Autolayout(VFL) 处理子视图居中
- CActiveXUI的一个Bug
- 关于一个多线程类的设计方法
- HashMap与HashTable解读(一)
- 南阳理工学院个人积分赛第四场【总结】
- 网络图片人脸识别并根据人脸焦点显示图片