拒绝Out Of Memory!为你的Android应用运行内存“瘦身”

 ——关于对图片进行处理以减小应用运行内存的心得

一、存在问题

      自己的APP大体完成后,该实现的基本功能都实现了,通过网络获取歌单信息、收藏歌单歌曲MV、听歌看MV、评论下载、修改个人信息等等功能也实现了。但是运行起来的效果不是很好,这个应用主界面的导航栏用了ViewPager嵌套ViewPager,同时加载了许多图片和从服务端获取的信息。因此每次返回到主界面都会崩溃,并报Out Of Merory(OOM)的错误。之前一直在完善各种功能,没怎么处理这个问题。等到现在,才发现,运行内存过大的话,APP的界面再好看,细节处理得再好也没用,因为用户在体验到这些亮点之前应用就已经崩溃了。所以解决运行内存过大的问题势在必行了。

二、问题分析

      根据网上获取的经验(《Android APP内存泄露之调试工具》这篇文章提供的方法去查看应用的内存使用情况),我查看到我的应用的内存是这样的:

右上角DDMS—选Device—待查项目—Heap选项查看内存情况

      其中“1-byte array(byte[],Boolean[])”这一行就是应用里图片占的运行内存,我的项目居然达到了58M多。如果我跳转到了其他页面,继续加载图片,使用的内存会继续增加,然后项目很快就崩溃了。Logcat里面报Out Of Merory(OOM)的错误。这是因为虚拟机对项目的运行内存有限制,最多96MB。换真机进行调试,同样用DDMS查看运行内存可以发现,项目运行占用的内存最高居然达到了120多MB,而图片资源更是占了80多MB,随着运行内存的增加,在手机上运行的项目也不出意料地崩溃了。点击1-byte array(byte[],Boolean[])一看,吓了一跳。最大一张图片居然占了8.789MB!即使把网络断了,让APP不加载网络图片,只加载项目本身的图片资源,内存情况也有36MB,最大一张图片也有4.932MB(如下图)。


不连接服务端的项目运行内存情况

      百思不得其解啊!我自己在PPT里设计的一些简单的矢量图只有10KB左右,就算有一些用PS处理过的用来做背景的图片,以及服务端传过来的歌单封面图片,也基本不超过100KB。为什么在内存里一张图片却占了4.932MB乃至8.789MB的内存呢?

      继续查资料,发现自己有一个认识误区,想当然地以为加载一张100KB的图片到ImageView里,占用的运行内存也只是100KB,其实不是这样的,事实上加载一张图片有可能要占用其大小许多倍的运行内存。其中具体的原理先不去了解,为了效率,先解决减小项目中图片资源占用内存过大的问题。

三、实验思路:

      为提高项目的运行效率,避免项目OOM崩溃影响用户体验。我新建了一个实验用的项目,通过以下实验去验证影响图片资源占用运行内存大小的因素。

      实验1、分别在同一页面加载两张内容相同、尺寸大小为100X100、格式分别为JPG和PNG的图片,对比其占用内存的大小;

      实验2、分别在同一页面加载两张内容相同、格式相同、尺寸分别为100X100,50X50的图片,对比其占用内存的大小;

      实验3、分别在同一页面加载两张内容相同、尺寸大小100X100、格式相同,第一次设置为visible,第二次设置为gone,对比其占用内存大小;

      实验4、分别在同一页面设置1个ImageView和10个ImageView,均加载同一张图片,对比其占用内存大小;  

      实验5、分别在两个页面设置同一个ImageView,加载同一张图片,从第一个页面跳转到第二个页面,对比其占用内存大小;

      实验6、分别在同一个页面用xml布局和Java代码去加载同一张图片,对比其占用内存大小;

      实验7、分别在同一页面用Java代码写加载同一张图片的方法,第一次,调用该方法,第二次不调用该方法;对比其占用内存的大小。

实验图片的属性(宽高、格式)可以从图片名看出,如图所示:

图片的内容


图片的大小(非尺寸大小)

四、实验结果:

实验1、第一次:test100jpg.Jpg  占用内存156.258KB

           第二次:test100png.png  占用内存156.258KB

实验2、第一次:test100jpg.Jpg  占用内存156.258KB

            第二次:test50jpg.jpg  占用内存39.070KB

实验3、第一次:test100jpg.Jpg  占用内存156.258KB

            第二次:test100jpg.jpg(gone)  占用内存156.258KB

实验4:第一次:test100jpg.Jpg  占用内存156.258KB

            第二次:test100jpg.jpg(10次)  占用内存156.258KB

实验5:第一次:test100jpg.Jpg (MainActivity)  占用内存156.258KB

            第二次:test100jpg.jpg(SecondActivity)  占用内存156.258KB

实验6:第一次:test100jpg.Jpg(在XML布局添加)  占用内存156.258KB

          第二次:test100jpg.jpg(在Java代码里用setImageResource()方法添加)占用内存156.258KB

实验7:第一次:test100jpg.Jpg(Java代码调用加载图片的方法)  占用内存156.258KB

           第二次:test100jpg.jpg(Java代码不调用加载图片的方法)  不占用内存

五、实验结论:

      1、图片占用的运行内存与图片格式无关。其实想想也知道,Android的图片资源对格式不敏感,加载图片只需要获取文件名,而不需要文件的格式后缀。

      2、图片占用的运行内存与图片尺寸大体成正比。内容相同,100X100的图片占用内存为156.258KB,100X100=10000,50X50的图片占用内存为39.070KB,50X50=2500,刚好都是4倍。

      3、图片的Visibility为gone,也需要占用相同内存。我们可以理解为先为ImageView这个图片控件加载了图片,然后再将这个控件设置为gone,因此,虽然ImageView控件被隐藏了,但是同样执行了图片的加载,因此需要占用内存。

      4、相同的图片,加载一次和加载多次均只占用相同的内存。

      5、相同的图片,只要加载过一次,即使在不同Activity继续加载,也只占用一份内存。

      6、在xml里加载图片与在Java代码里用setImageResource()方法添加图片,所占用内存大小相同。

      7、如果Java代码里加载图片的方法不被调用,则不需要占用内存空间。

六、对策方法:

      根据以上的结论,再检查自己项目里的图片资源文件,发现了许多问题。比如我为求自己做的APP界面好看一点,用PPT画一些简单的矢量图,毕竟在网上直接找的图标,底色是白色的,而自己的APP的背景色有可能是别的颜色,唯有用PPT画一些矢量图,把填充色改为透明。然而这样做出来一些图标之后,虽然只有10KB不到,但是尺寸达到了400X400这个尺度,刚开始通过DDMS的heap up查询到的占用了4.932MB内存的图片,后来发现只是一张9KB,尺寸为433X389的矢量图。这些图片的尺寸并没有根据所要加载的控件大小去进行合理地设置,比如“播放”这一个ImageView控件的大小仅为60dpX60dp,那么“播放”这个图标的尺寸为400X400就没有必要了,完全可以将其的尺寸缩小。

      根据发现的问题,做出了以下几点修改:

      1、按照要加载的控件大小去重新设置图标的尺寸。

      2、服务端的图片比如歌单封面、用户头像等也根据加载的控件大小去设计图标尺寸。

      3、有些控件刚开始是不显示或者不被用户使用的,可以不在XML布局加载图片,而是在Java代码里面去加载图片。

七、总结:

      经过调整,应用的运行内存大大减少。其中不连接网络,只加载本地图片资源的情况下,主界面的图片占用内存为2.590MB,连接网络后,主界面的图片占用内存也仅为8.595MB,相比优化前大大减少。


只加载本地图片资源


加载本地和网络图片资源

      为项目瘦身之后,顿时感觉神清气爽!立竿见影的是项目能够来回顺畅切换,而不至于因为内存溢出而崩溃了,终于可以继续优化自己的项目啦!接下来还是要在图片清晰度和内存使用合理程度上找到平衡,既保持界面的美观,也要保证应用能够顺畅运行,避免崩溃。毕竟自己当时也是没注意图片的尺寸,看到图片内容OK就直接往资源文件夹塞,所以希望这篇文章能够为Android的初学者提供一点帮助。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,458评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,454评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,171评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,062评论 0 207
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,440评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,661评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,906评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,609评论 0 200
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,379评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,600评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,085评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,409评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,072评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,088评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,860评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,704评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,608评论 2 270

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,569评论 25 707
  • 九寨沟的宾馆里,独坐案头,竟有些哭泣的感觉。或许微小的事件牵动内心底层沉积的乱麻;或许是成都的天气有些阴冷,把我冻...
    白袍女巫阅读 197评论 2 4
  • 我开玩笑说,如果你们找教练来推动组织变革,找个“不怕死”的吧(不怕挑战高管),既使这样我估计成功率也很低。他又沉默...
    BigSpirit阅读 326评论 1 1
  • 夏日入夜 微凉的细风抚断了雨丝 有人穿过幽静清香的槐树林 孑然一身 泛白路灯下雨露均沾的绿草坪 雨雾蒙蒙 藏着一只...
    北山月阅读 150评论 0 4
  • 过去10年了,当时考研的一幕幕对我记忆犹新。说实话,如果不是过去了这么多年,这段经历我是不想提,更是不愿别人谈论的...
    小雨读书写作阅读 5,380评论 14 39