java中的引用和GC
2016-01-25 11:40
453 查看
java中的引用和GC
简介:java中有四种引用:强软弱虚强引用: strong Reference,=就是强引用方式,即时出现OOM,GC都不会销毁强引用
软引用: soft Reference,当Java所管理的内存趋于阈值时,GC将会销毁一部分软引用,释放内存。
弱引用: weak Reference,就算Java所管理的内存没有趋于阈值,GC都有可能销毁部分弱引用。
虚引用: 按照GC回收优先度,虚引用肯定是最早被回收的,这个基本开发的时候不会用到
GC:Garbage Collection,是java和C++的主要区别之一,这里简单介绍一下,如果有时间再去写详细介绍,
垃圾回收机制,java程序员不需要去自己回收内存,不想C和C++的程序员,但是电脑去执行回收机制肯定做不到人那样根据需要去回收,所以会造成一定程序的内存浪费,这就是为什么对安卓里面的OOM很重视。
GC在执行的时候模,所有的线程都会被暂停。当Java所管理内存趋于阈值时,GC的执行频率将会加快,这时候就会出现卡顿的感觉,用户体验杀手。
下面结合一些代码讲一下这个问题
早期的时候,图片显示是手机的一个大问题,因为早期手机内存过小,后来出现了高压缩率的图片jpg之类的图片问题得到部分改善,后来内存又扩大,这个问题基本得到了解决,但是随着时间,图片的数量越来越多,再结合服务器,考虑到流量问题。下面具体分析listview结合服务器的图片下载问题
首先,listview采用了viewholder和adapter进行了优化,但是如果涉及到图片,如果单纯的把图片存在RAM部分,那么加载速度会非常慢,而listview的滑动操作是很快的,这时候就会出现图片没有加载完成所显示的view就不需要了,影响用户体验,之前有写过解决这个问题的方法,是采用了异步任务加中断的方式,但是这种情况适用性有限,而且不好用,性能提升不明显
3. 速度慢的原因是需要去ram中读取的图片的速度过慢导致,所以想到一个办法,将图片存入内存,但当图片过多的时候会出现OOM问题,java程序员是没有办法回收不用的图片内存的,GC这个时候也不会去回收强引用,所以要使用软应用甚至弱引用来解决,这其实是一个二级缓存机制,具体请看下面的代码
package cn.myapp.musicclient.util; import java.io.File; import java.io.IOException; import java.lang.ref.SoftReference; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import org.apache.http.HttpEntity; import org.apache.http.client.ClientProtocolException; import org.apache.http.util.EntityUtils; import com.tarena.musicclient.R; import android.content.Context; import android.graphics.Bitmap; import android.os.Handler; import android.os.Message; import android.util.Log; import android.widget.AbsListView; import android.widget.ImageView; import android.widget.ListView; /** * 图片异步批量加载的工具类 * 提供图片的内存缓存与文件缓存 */ public class ImageLoader { //声明工作线程 private Thread workThread; private boolean isLoop=true; //存储缓存图片 private HashMap<String, SoftReference<Bitmap>> cache=new HashMap<String, SoftReference<Bitmap>>(); private Context context; //生成任务集合 private List<ImageLoadTask> tasks=new ArrayList<ImageLoadTask>(); private AbsListView listView; //声明handler private Handler handler=new Handler(){ public void handleMessage(android.os.Message msg) { switch (msg.what) { case HANDLER_IMAGE_LOAD_SUCCESS: //更新ImageView ImageLoadTask task=(ImageLoadTask)msg.obj; //通过position做的tag 找到相应的ImageView ImageView ivAlbum=(ImageView)listView.findViewWithTag(task.position); if(ivAlbum!=null){ Bitmap bitmap=task.bitmap; if(bitmap!=null){ ivAlbum.setImageBitmap(bitmap); }else{ ivAlbum.setImageResource(R.drawable.ic_launcher); } } break; } } }; public static final int HANDLER_IMAGE_LOAD_SUCCESS=0; public ImageLoader(Context context, AbsListView listView) { this.listView=listView; this.context=context; //初始化workThread workThread=new Thread(){ public void run() { //不断的查看集合中是否有数据 while(isLoop){ //如果集合中有图片下载任务 if(!tasks.isEmpty()){ //把第一个图片下载任务获取并执行 ImageLoadTask task=tasks.remove(0); //直接下载图片 Bitmap bitmap=loadBitmap(task.path); //把bitmap设置到相应的ImageView中 //需要在主线程中 (发消息给handler) task.bitmap=bitmap; Message msg=new Message(); msg.what=HANDLER_IMAGE_LOAD_SUCCESS; msg.obj=task; handler.sendMessage(msg); }else{ //如果任务集合中已经没有任务了 //那么线程等待 synchronized (workThread) { try { workThread.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } } }; workThread.start(); } /** * 通过path 发送http请求 下载图片 * @param path * images/junshengjinshi.jpg * @return * @throws IOException * @throws ClientProtocolException */ public Bitmap loadBitmap(String path) { try { String url=GlobalConsts.BASEURL+path; HttpEntity entity=HttpUtils.send(HttpUtils.METHOD_GET, url, null); //把entity转成Bitmap byte[] bytes=EntityUtils.toByteArray(entity); Bitmap bitmap=BitmapUtils.loadBitmap(bytes, 50, 50); //向内存缓存中 缓存图片 cache.put(path, new SoftReference<Bitmap>(bitmap)); //向缓存目录中 保存图片 File targetFile=new File(context.getCacheDir(), path); //targetFile: /data/data/com.xx.xx/cache/images/jsjs.jpg BitmapUtils.save(bitmap, targetFile); return bitmap; } catch (IOException e) { e.printStackTrace(); } return null; } /** * 显示图片 * @param imageView 控件 * @param path 图片路径 * @param position 图片的位置 */ public void displayImage(ImageView imageView, String path, int position){ imageView.setTag(position); 4000 //从缓存中获取 如果有 则直接显示 //不在向任务集合中添加任务了。 SoftReference<Bitmap> ref=cache.get(path); if(ref!=null){ Bitmap bitmap=ref.get(); if(bitmap!=null){ Log.i("info", "这是从内存缓存中读取的图片.."); imageView.setImageBitmap(bitmap); return; } } //内存缓存中没有图片 则去文件缓存中读取 String filepath=new File(context.getCacheDir(),path).getAbsolutePath(); Bitmap bitmap=BitmapUtils.loadBitmap(filepath); if(bitmap!=null){ Log.i("info", "从文件缓存中读取的图片.."); imageView.setImageBitmap(bitmap); //存入内存缓存 cache.put(path, new SoftReference<Bitmap>(bitmap)); return; } //向任务集合中添加任务 ImageLoadTask task=new ImageLoadTask(); task.path=path;//保存图片路径 task.position=position; tasks.add(task); //唤醒工作线程workThread 起来干活 synchronized (workThread) { workThread.notify(); } } class ImageLoadTask{ String path; Bitmap bitmap; int position; } public void stopThread() { isLoop=false; synchronized (workThread) { workThread.notify(); } } }
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- c++11 + SDL2 + ffmpeg +OpenAL + java = Android播放器
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序
- 二叉查找树