android中的内存优化

RAM管理是开发者们从程序设计到上线运营都要头疼的一块,实际开发中,机佬们各取手段,不断变换设计和实现方式,而这些方式的技术要点总结起来主要为以下十五招。

1.Service的合理使用

很多developer都会使用Service与android内存管理员拉锯作战,这是邪教武功,不宜长久。一个service被启动后,系统在资源紧张释放内存时,会一直保留Service所在的进程,使进程运行的代价提高,减少了系统能存放到LRU缓存当中的进程数量,进而影响app之间的切换效率,用户就会发现,有几款app常驻后台,而现在手机已经很卡了,马上就会考虑卸载它们。

一个清爽的app中,service的使用方式是IntentService,它会在处理完交给它的intent后尽快结束自己。

2.UI隐藏时释放内存

当应用被切换并不可见后,释放UI占用的资源,可以很大程度的提高系统缓存进程的能力,用户体验就来了。

需要实现Activity类中的 onTrimMemory( ) 回调方法,在这个方法中,监听 TRIM_MEMORY_UI_HIDDEN级别的回调,通过这可以接收用户离开UI的通知。

与onStop( ) 中释放资源不一样,onStop( ) 会在你的同一个app内某一个Activity跳到另一个Activity时调用,并释放Activity里的资源,如网络连接、unregister广播接受者等。除非收到onTrimMemory( ) ,否则不应该释放UI资源,这可以确保用户从当前app内其它Activity切换回来时,Activity能迅速恢复。

3.内存紧张时释放部分内存

app运行时,在生命周期的任何阶段,都可以调用onTrimMemory( ) 获取整个设备内存资源状况。根据不同的状况,灵活使用手段,可以提高app存活率和体验效果。

TRIM_MEMORY_RUNNING_MODERATE
你的app正在运行并且不在死亡清单中。但是,系统处于低内存状态,开始触法杀死LRU Cache中的Process机制

TRIM_MEMORY_RUNNING_LOW
你的app正在运行并且不在死亡清单中。但是,系统处于低内存状态,应该释放不用的资源以提高系统性能(但是会直接影响你的app的性能)。

TRIM_MEMORY_RUNNING_CRITICAL
你的app仍在运行,但是,系统已经杀死LRU Cache中的大多数进程,如果系统回收不到足够的RAM数量,将会清除所有LRU缓存中的进程,并且开始杀死之前判断不应该杀死的进程,如:包换正在运行状态的Service的进程。
此时应该释放所有非必须的资源,维持系统生态的和谐。

当你的app正在被cached时,可能收到以下几种状态值:

TRIM_MEMORY_BACKGROUND
系统处于低内存状态,你的app处于LRU缓存名单中最不容易杀掉的位置。

TRIM_MEMORY_MODERATE
系统处于低内存状态,你的app处于LRU缓存名单中部位置。应该释放不用的资源以提高系统性能(但是会直接影响你的app的性能)。

TRIM_MEMORY_COMPLETE
系统处于低内存状态,你的app处于LRU缓存名单中最容易杀掉的位置。此时应该释放掉任何不影响app恢复状态的资源以保全自己。

4.扩展heap空间

不同的设备为app提供的不同的heap限制,可以使用getMemoryClass( ) 来获取app的可用heap大小。如果你的app尝试使用更多的内存,就会出现OOM。

特殊的应用需要使用更大heap时,可以在manifest的application标签下添加 "largeHeap = true" 的属性来声明一个更大的空间,通过getLargeMemoryClass( ) 来获取一个更大的heap size。

这个方法如非必要,不可轻易使用,否则造成资源冗余,你的app的存在会影响整个系统的体验,每次GC运行时间更长,任务切换时系统性能也会降低,间接增加了app被卸载的危险。

5.bitmap合理使用

加载一个bitmap时,仅仅需要保留适配当前屏幕分辨率的数据即可。增加bitmap的尺寸会对内存呈现2次方的增加,因为XY都在增加。

图片加载功能的实现,建议使用ImageLoader框架,如Picasso、Glide等成熟的框架。

6.使用优化的数据容器

利用Android Framework里优化过的容器类,如SparseArray、SparseBooleanArray、LongSparseArray。

通常的HashMap的实现方式更加消耗内存,因为它需要一个额外的实力对象来记录Mapping操作。另外,sparseArray更加高效在于它们避免了对key、value的autobox,并避免了装箱后的解箱。

7.时刻注意各种内存开销

许多小细节都可能会导致大量的内存开销,因此必须对语言与库的开销有所了解,内存开销的控制应该贯穿始末。如:Enums的内存消耗通常是static constants的2倍,应该尽量避免在android中使用enums;Java中的每一个类(包括匿名内部类)都会使用大概 500 bytes;每一个类的实例产生的花销是12~16bytes;往HashMap中添加一个entry需要额外占用的32 bytes的entry对象等。

8.注意代码“抽象”

代码抽象会提升代码的灵活性和可维护性,但会导致一个显著的开销:通常它们需要同等量的代码用于可执行,那些代码会被map到内存中。因此,如果抽象没有显著提升效率,应该尽量避免它们。

9.为序列化的数据使用nano protobufs

通常的协议化操作会产生大量繁琐的代码,app就有很多隐藏的弊端:增加RAM使用量,APK太肥,执行速度缓慢,容易达到DEX字符限制等。

protocol buffers 是google为序列化结构数据而设计的,与语言、平台等无关,类似xml,却更轻量、快速、简单。如果数据需要实现序列化,那么代码中应该经常出现 nano protobufs。

10.避免使用依赖注入框架

现在有很多优秀的框架,能提升开发体验、减轻开发量、让代码更优雅,但是这些框架会通过扫描你的代码,执行很多初始化的操作,这回导致你的代码需要大量的RAM来map代码。但是,mapped pages会长时间的被保留在RAM中。

11.谨慎使用外部库

很多library的代码都不是为移动开发环境编写的,因此,运用到移动开发时会影响app的效率。即使针对android而设计的library,也会因为几个library所做的事不一样,从而影响到你的app。如一个lib使用的是nano protobufs,另一个lib使用micro protobufs,那么,你的app中就会有两种protobuf实现方式。这样的冲突可能会发生在输出日志、加载图片、缓存等模块上。

因此,如果不是需要大量使用这个库来达到开发效果,只为了一个两个功能而导入整个library,是非常不明智的,此时自己实现这个功能是最佳选择。

12.整体性能的优化

谷歌官方列出了许多优化整个App性能的文章,诸如 Best Practices for Performance

还有些文章是讲解如何优化App 的CPU使用效率,有些是讲解如何优化App 的内存使用效率。

optimizing your UI是讲解如何为layout进行优化。

13.使用ProGuard剔除冗余代码

ProGuard可以通过剔除不需要的代码,重命名类、域与方法等对代码进行压缩、优化与混淆。可以使用更少的mapped代码所需要的RAM。

14.对最终的apk使用zipalign

zipalign可以对apk二次校准,减少app需要的RAM的。

15.使用多进程

特殊需要才可用这一招,因为大多数的app如果使用多进程,反而会增加内存的使用。当app需要在后台运行与前台一样的大量的任务时,可以考虑使用这个技术。如音乐播放的app,如果整个app运行在一个进程中,后台播放时,前台的UI无法释放,增加RAM负担。这样的app可以分成两个进程,一个操作前台UI,另一个用于后台Service。

可以在manifest文件中声明"android:process"属性来实现某个组件运行在另外一个进程的操作:

<service android:name=".PlaybackService" android:process="background" />

以上十五招需合理使用,开发过程中时刻考虑内存状况,各个阶段都做好内存管理,这样的app才会更健壮、更简洁、更高效。

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

推荐阅读更多精彩内容