android 慎用drawable中大图,造成内存溢出的解决方案
来源:互联网 发布:nginx 子域名跨域配置 编辑:程序博客网 时间:2024/06/03 21:14
叨叨
drawable中存放一些本地图片,用来在需要的地方调用,这是很常见的用法。
而近期,新版本应用即将上线,因此我将应因上传至阿里移动质检平台测试了一翻,检测出来的问题并不是很多,但在30台机器中,有三次内存溢出的情况出现,这让我很担心。
点开后查看详情:
分析
通过上图大致知道是引导页面出现的问题。为了更好的分析原因,决定通过MAT工具来分析内存占用情况。
在android studio中通过Android Monitor界面(查看log日志的那个)中的Monitors中的Dump java heap按钮,就可以在应用运行过程中实时的捕获内存的hprof文件。
捕获后可以在界面左侧的capture中看到文件
找到文件,通过sdk中的platform-tools文件夹内的hprof-conv工具来转换文件
在此文件夹内按住shift 同时鼠标右键点击打开命令行界面
输入 hprof-conv 你的源hprof文件路径.hprof 目标路径.hprof
就可以完成转换了。
下面就可以通过MAT(Memory Analyaer Tool)工具来分析。MAT工具下载
MAT分析
点击左下侧的histogram,看到byte[]相对于其它占用了大量的内存
右键点击byte[],选择List objects-->with incoming references(如果到这里有类似:MAT是啥?不认识啊!等感觉,那么可以先自行去查一下MAT工具的使用了,这里不作详细说明)
打开之后如下
很明显,占用内存的大头就是前面几个,点开看看
发现bitmap,原来就是图片的原因(大多数内存溢出都是这个原因 0.0)
为了看是哪个图片,这里要借助一个图片工具:GIMP 下载点这里
选中mBuffer
然后右边会出现这个:
嗯,再右键我上面红箭头指向的mBuffer选项
把数据保存为文件,注意了,要以xxx.data形式保存
然后打开GIMP把这个bitmap.data拖进去
会出现这个:
选中RGB Alpah ,另外看到宽高这里,通过MAT工具是可以知道数据的,回到MAT,还是选中那个mBuffer,找到数据填进去就可以
填 好后,已经可以看到图片了:
(注意,为了自已的小隐私,这里打码了)
已经知道了,这就是引导页面的图片,但是查看文件
有7.9MB,天,我传到drawable去的时候只有100kb,怎么回事呢,然后看下另外的byte[]
全是一样的大小,说明不是图片的问题,应该是调用过程中的问题。
查看代码,这里引导页面是用viewpager实现的,这里只贴instantiateItem()的代码:
@Override public Object instantiateItem(ViewGroup container, int position) { .... view.setImageResource(mGuides[position]); .... }
看来看去只发现view.setImageResource(mGuides[position]);这代码是用来设置图片的,问题应该就出在这里了。
原因
是在drawable中直接引用的,去查了一翻之后,原来直接使用setImageResource方法,最终都是通过java层的createBitmap来完成的,需要消耗更多内存。
解决方法:
改用先通过BitmapFactory.decodeStream方法,创建出一个bitmap,再将其设为ImageView的 source,
查看一下decodeStream方法的源码:
public static Bitmap decodeStream(InputStream is, Rect outPadding, Options opts) { // we don't throw in this case, thus allowing the caller to only check // the cache, and not force the image to be decoded. if (is == null) { return null; } Bitmap bm = null; Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "decodeBitmap"); try { if (is instanceof AssetManager.AssetInputStream) { final long asset = ((AssetManager.AssetInputStream) is).getNativeAsset(); bm = nativeDecodeAsset(asset, outPadding, opts); } else { bm = decodeStreamInternal(is, outPadding, opts); } if (bm == null && opts != null && opts.inBitmap != null) { throw new IllegalArgumentException("Problem decoding into existing bitmap"); } setDensityFromOptions(bm, opts); } finally { Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS); } return bm; }
发现decodeStream最大的秘密在于其直接调用JNI>>nativeDecodeAsset()来完成decode,
无需再使用java层的createBitmap,从而节省了java层的空间。
通过这个方法:
public static Bitmap readBitMap(Context context, int resId) {BitmapFactory.Options opt = new BitmapFactory.Options();opt.inPreferredConfig = Bitmap.Config.RGB_565;opt.inPurgeable = true;opt.inInputShareable = true;//获取资源图片InputStream is = context.getResources().openRawResource(resId);return BitmapFactory.decodeStream(is, null, opt);}
获得bitmap后设置给imageview,就可以了。
再查看内存:
发现从原先的52MB,减小到了14.4MB。原先加载一张图片需要7.9MB,总共5张,大概要40MB,这里就节约了近40MB的内存。
总结
- android 慎用drawable中大图,造成内存溢出的解决方案
- android 慎用drawable中大图,造成内存溢出的解决方案
- android 大图片在listview中内存溢出的问题
- android 大图片在listview中内存溢出的问题
- android 解决大图内存溢出的总结
- Android在加载大图片时,易出现内存溢出的情况 解决方案一
- Android在加载大图片时,易出现内存溢出的情况 解决方案
- 下载大量图片内存溢出的解决方案(使用SoftReference<Drawable>)
- android中避免大图片解析导致内存溢出 OutOfMemoryError的优化方法
- Android开发中如何解决加载大图片时内存溢出的问题
- Android开发中如何解决加载大图片时内存溢出的问题
- Android开发中如何解决加载大图片时内存溢出的问题
- Android开发中如何解决加载大图片时内存溢出的问题
- 解决android中加载大图时出现的内存溢出问题
- Android开发中大图片所引起的内存溢出问题
- Android开发中如何解决加载大图片时内存溢出的问题
- Android中图片过大造成内存溢出常用解决方法
- android中由于下载图片造成的内存溢出的解决方法
- 坑爹的不受限字符串函数
- C++数据类型
- Activity传递对象的方法《转载》
- 数组名与数组名取地址的差异
- In-memory Computing with SAP HANA读书笔记 - 第三章:Software components and data replication methods
- android 慎用drawable中大图,造成内存溢出的解决方案
- EventBus使用详解(一)——初步使用EventBus
- [swift学习之九]异常处理
- mac Homebrew
- [SCU 4504] 奶牛合影 (最小表示法)
- Python实现杨辉三角形
- Concurrent包中Queue(2)----ArrayBlockingQueue
- red hat linux使用yum 出现Loaded plugins: rhnplugin, security
- 如何提高循环效率