240 likes | 601 Views
android 内存管理. ── 朱鹏. 自我介绍. 朱鹏. Android 开发工程师 qq : 752061935 手机 : 15618953973. 二手房. 租房. 新房. Why. Android 系统有自己的垃圾回收机制,可以自动回收内存空间。那为什么还需要专门做个针对内存管理做一个分享呢? 答案很简单: crash!!!. Bitmap. 谈到 android 内存管理这里不得不提的一个对象就是 Bitmap 。 内存大户
E N D
android内存管理 ──朱鹏
自我介绍 朱鹏 Android开发工程师 qq : 752061935 手机 : 15618953973 二手房 租房 新房
Why Android系统有自己的垃圾回收机制,可以自动回收内存空间。那为什么还需要专门做个针对内存管理做一个分享呢? 答案很简单: crash!!!
Bitmap 谈到android内存管理这里不得不提的一个对象就是Bitmap。 内存大户 而一个andriod程序运行过程中所占用的内存(native+dalvik)超过>16M(默认) OOM
查看内存使用情况 adb shell dumpsys meminfo $package_name or $pid
Bitmap对象 bitmap对象 linux底层C内存 android虚拟机 (DVM)
recycle() 首先明确一点无论你调用不调用recycle()方法,android程序都不会内存泄露。 recycle只做了一件事:The bitmap is marked as 'dead'。 recycle真的用途在于:它可以帮助GC快速决定是否回收这个对象,当一个应用包含大量的图片的时候,这个方法还是很有作用的,因为GC并没有你想象的聪明。
recycle()具体使用 // 先判断是否已经回收 if(bitmap != null && !bitmap.isRecycled()){ // 回收并且置为null bitmap.recycle(); bitmap = null; }
这里再介绍一个比较实用的方法 if(imageView != null && imageView.getDrawable() != null){ Bitmap oldBitmap = ((BitmapDrawable) imageView.getDrawable()).getBitmap(); imageView.setImageDrawable(null); if(oldBitmap != null){ oldBitmap.recycle(); } }
建议在一个大量使用图片的应用中activity继承以下BaseActivity建议在一个大量使用图片的应用中activity继承以下BaseActivity public class BaseActivity{ ArrayList<SoftReference<Bitmap>> bitmapCache = new ArrayList<SoftReference<Bitmap>>(); @Override protected void onDestroy() { for(SoftReference<Bitmap> sb:bitmapCache ){ 回收操作 } super.onDestroy(); } }
bitmap什么时候会导致程序OOM 单张图片过大 解决方案: 1、调整dvm单个堆栈大小 2、压缩图片 3、切割图片 小图片累积过多 解决方案: 1、用完即手动recycle
图片压缩小技巧 在使用BitmapFactory压缩图片的时候,BitmapFactory.Options设置inJustDecodeBounds为true后,再使用decodeFile()等方法,可以在不分配空间状态下计算出图片的大小。示例: BitmapFactory.Options opts = new BitmapFactory.Options(); // 设置inJustDecodeBounds为true opts.inJustDecodeBounds = true; // 使用decodeFile方法得到图片的宽和高 BitmapFactory.decodeFile(path, opts); // 打印出图片的宽和高 Log.d("example", opts.outWidth + "," + opts.outHeight); (ps:原理其实就是通过图片的头部信息读取图片的基本信息)
Bitmap在listview和gallery中的典型使用 Map<String, SoftReference<Bitmap>> mBitmapList ; public void loadImage(imageView,url){ 1、根据url从内存即mBitmapList 读取地图,如果内存没有读到图片则进行第二步。 2、根据url读取本地图片,如果没有读取到,则进行第三步。 3、将url加入下载队列,下载成功后将bitmap加入内存缓存即mBitmapList 。 } ps:在listview和gallery滑动的过程中可以不断手动recycle()不用的bitmap对象,维持内存缓存mBitmapList 固定大小,这样可以减小oom发生的概率。
gallery的问题 经过以上处理之后你会发现listview很好用了,很难在发生OOM。但是你会发现一个问题,这种方法在gallery上总是不好用,要不是出现OOM,就是抛出异常try to recycle a using bitmap。 这是为什么呢?
gallery相关的adapter的常见写法 class GalleryAdapter extends BaseAdapter{ public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; if(convertView==null){ holder = new ViewHolder(); holder.photo = new Imageview(); convertView.setTag(holder ); }else{ holder = (ViewHolder) convertView.getTag(); } return holder.photo; } }
原因分析 Gallery:没有实现convertView的复用。 if(convertView==null){...永远进入这段代码执行...} 这点值得所有android开发工程师注意,一不小心就掉入陷阱里面了。
"软引用失效" 软引用 hashmap bitmap imageview 强引用 因为gallery本身没有实现view的复用导致程序会new很多个imageview,而只有当imageview被释放的时候和他绑定bitmap才有可能被释放。当你强行通过recycle释放bitmap时,就会导致try to recycle a using bitmap异常。
gallery推荐使用以下代码 private ArrayList<ImageView> mImageViewList = new ArrayList<MyImageView>(); public View getView(int position, View convertView, ViewGroup parent) { if(mImageViewList.get(nowPosition) == null){ imageView = new MyImageView(mContext); mImageViewList.set(nowPosition, imageView); } else { imageView = (MyImageView) mImageViewList.get(position % mImageViewList.size()); } return imageView; } 通过使用ArrayList达到imageView复用的目的。
再次强调 禁止出现占据大块内存的不能释放的引用,尤其是静态引用特别注意,特别有些同学喜欢把某个activity的context赋值某个静态变量,直接导致这个activity的生命周期延长至整个程序期间,占据大量内存。 使用bitmap软引用自动释放的时候,要确保引用该bitmap的view能及时释放,这样bitmap才有机会被释放,最好采用手动recycle方式。