优化Android应用内存的若干方法
2014-07-14 13:33
204 查看
原文
优化Android应用内存的若干方法
您的评价: | 较差 | 收藏该经验 |
使用保守的Service
如果你的应用需要使用并且,当你的service执行完成但是停止失败时要小心service导致的内存泄露问题.
当你启动service时,系统总是优先保持服务的运行.这会导致内存应用效率非常低,因为被该服务使用的内存不能做其它事情.也会减少系统一直保持的LRU缓存处理数目,使不同的app切换效率降低.当前所有service的运行会导致内存不够不能维持正常系统的运行时,
系统会发生卡顿的现象严重时能导致系统不断重启.
最好的方式是使用
当使用intent开始任务后,该service执行完所有的工作时会自动停止.
在android应用中当不需要使用常驻service执行业务功能而去使用一个常驻service是最糟糕的内存管理方式之一.所以不要贪婪的使用service使你的应用一直运行状态.这样不仅使你因为内存的限制提高了应用运行的风险,也会导致用户发现这些异常行为后而卸载应用.
当视图变为隐藏状态后释放内存
当用户跳转到不同的应用并且你的视图不再显示时,你应该释放应用视图所占的资源.这时释放所占用的资源能显著的提高系统的缓存处理容量,并且对用户的体验质量有直接的影响.
当实现当前
用户离开视图时会得到通知.使用该方法可以监听
当你的视图元素从父视图中处于隐藏状态时释放视图所占用的资源.
注意只有当你应用的所有视图元素变为隐藏状态时你的应用才能收到
这个和
或者有用户移动到应用中的另外的activity才会引发.所以说你虽然实现了
的资源例如网络连接或者未注册的广播接收者,但是应该直到你收到
这里可以确定的是如果用户通过后退键从另外的activity进入到你的应用中,视图资源会一直处于可用的状态可以用来快速的恢复activity.
内存资源紧张时释放内存
在应用生命周期的任何阶段你可以根据该方法推送的内存紧张级别来释放资源.
TRIM_MEMORY_RUNNING_CRITICAL
应用处于运行状态并且不会被杀掉,设备使用的内存比较低,系统级会杀掉一些其它的缓存应用.
TRIM_MEMORY_RUNNING_LOW
应用处于运行状态并且不会被杀掉,设备可以使用的内存非常低,可以把不用的资源释放一些提高性能(会直接影响程序的性能)
TRIM_MEMORY_RUNNING_CRITICAL
应用处于运行状态但是系统已经把大多数缓存应用杀掉了,你必须释放掉不是非常关键的资源,如果系统不能回收足够的运行内存,系统会清除所有缓存应用并且会把正在活动的应用杀掉.
还有,当你的应用被系统正缓存时,通过
TRIM_MEMORY_BACKGROUND
系统处于低内存的运行状态中并且你的应用处于缓存应用列表的初级阶段.虽然你的应用不会处于被杀的高风险中,但是系统已经开始清除缓存列表中的其它应用,所以你必须释放资源使你的应用继续存留在列表中以便用户再次回到你的应用时能快速恢复进行使用.
TRIM_MEMORY_MODERATE
系统处于低内存的运行状态中并且你的应用处于缓存应用列表的中级阶段.如果系运行内存收到限制,你的应用有被杀掉的风险.
TRIM_MEMORY_COMPLETE
系统处于低内存的运行状态中如果系统现在没有内存回收你的应用将会第一个被杀掉.你必须释放掉所有非关键的资源从而恢复应用的状态.
因为
api中加入的,所以低版本的要使用
该方法大致相当于
注意:当系统开始清除缓存应用列表中的应用时,虽然系统的主要工作机制是自下而上,但是也会通过杀掉消费大内存的应用从而使系统获得更多的内存,所以在缓存应用列表中消耗更少的内存将会有更大的机会留存下来以便用户再次使用时进行快速恢复.
检查可以使用多大的内存
前面提到,不同的android设备系统拥有的运行内存各自都不同,从而不同的应用堆内存的限制大小也不一样.你可以通过调用如果你想获取超过最大限度的内存则会发生
有一个特别的情况,可以在manifest文件中的
"true"时,当前应用就可以获取到系统分配的最大堆内存.如果你设置了该值,可以通过ActivityManager的
然后,只有一小部分应用需要消耗大量堆内存(比如大照片编辑应用).从来不需要使用大量内存仅仅是因为你已经消耗了大量的内存并且必须快速修复它,你必须使用它是因为你恰好知道所有的内存已经被分配完了而你必须要保留当前应用不会被清除掉.甚至当你的应用需要消耗大量内存时,你应该尽可能的避免这种需求.使用大量内存后,当你切换不同的应用或者执行其它类似的操作时,因为长时间的内存回收会导致系统的性能下降从而渐渐的会损害整个系统的用户体验.
另外,大内存不是所有的设备都相同.当跑在有运行内存限制的设备上时,大内存和正常的堆内存是一样的.所以如果你需要大内存,你就要调用
避免在bitmaps中浪费内存
当你加载bitmap时,需要根据分辨率来保持它的内存时最大为当前设备的分辨率,如果下载下来的原图为高分辨率则要拉伸它.要小心bitmap的分辨率增加后所占用的内存也要进行相应的增加,因为它是根据x和y的大小来增加内存占用的.注意:在Android2.3.x(apilevel10)以下,无论图片的分辨率多大bitmap对象在内存中始终显示相同大小,实际的像素数据被存储在底层native的内存中(c++内存).因为内存分析工具无法跟踪native的内存状态所有调试bitmap内存分配变得非常困难.然而,从Android3.0(apilevel11)开始,bitmap对象的内存数据开始在应用程序所在Dalvik虚拟机堆内存中进行分配,
提高了回收机率和调试的可能性.如果你在老版本中发现bitmap对象占用的内存大小始终一样时,切换设备到系统3.0或以上来进行调试.
使用优化后的数据容器
利用Android框架优化后的数据容器,比如传统的
知道内存的开销
在你设计应用各个阶段都要很谨慎的考虑所使用的语言和库带来的内存上的成本和开销.通常情况下,表面上看起来无害的会带来巨大的开销,下面在例子说明:当枚举(enum)成为静态常量时超过正常两倍以上的内存开销,在android中你需要严格避免使用枚举
java中的每个类(包含匿名内部类)大约使用500个字节
每个类实例在运行内存(RAM)中占用12到16个字节
在hashmap中放入单项数据时,需要为额外的其它项分配内存,总共占用32个字节
使用很多的不必要类和对象时,增加了分析堆内存问题的复杂度.
当心抽象代码
通常来说,使用简单的抽象是一种好的编程习惯,因为一定程度上的抽象可以提供代码的伸缩性和可维护性.然而抽象会带来非常显著的开销:需要执行更多的代码,需要更长时间和更多的运行内存把代码映射到内存中,所以如果抽象没有带来显著的效果就尽量避免.使用纳米Protocol
buffers作为序列化数据
更快,更简单.如果你决定使用它作为你的数据,你必须在你的客户端代码中一直使用纳米protocolbuffer,因为正常的protocolbuffer会产生极其冗余的代码,在你的应用生会引起很多问题:增加了使用的内存,增加了apk文件的大小,执行速度较慢以及会快速的把一些限定符号打入dex包中.
尽量避免使用依赖注入框架
使用像因为它使我们可以写一些更简单的代码和提供自适应的环境用来进行有用的测试和进行其它配置的更改.然而这些框架通过注解的方式扫描你的代码来执行一系列的初始化,但是这些也会把一些我们不需要的大量的代码映射到内存中.被映射后的数据会被分配到干净的内存中,放入到内存中后很长一段时间都不会使用,这样造成了内存大量的浪费.
谨慎使用外部依赖库
许多的外部依赖库往往不是在移动环境下写出来的,这样当在移动使用中使用这些库时就会非常低效.所以当你决定使用一个外部库时,你就要承担为优化为移动应用外部库带来的移植问题和维护负担.在项目计划前期就要分析该类库的授权条件,代码量,内存的占用再来决定是否使用该库.甚至据说专门设计用于android的库也有潜在的风险,因为每个库做的事情都不一样.例如,一个库可能使用的是nanoprotobuf另外一个库使用的是microprotobuf,现在在你的应用中有两个不同protobuf的实现.这将会有不同的日志,分析,图片加载框架,缓存,等所有你不可预知的事情的发生.Proguard不会保存你的这些,因为所有低级别的api依赖需要你依赖的库里所包含的特征.当你使用从外部库继承的activity时尤其会成为一个问题(因为这往往产生大量的依赖).
库要使用反射(这是常见的因为你要花许多时间去调整ProGuard使它工作)等.
也要小心不要陷入使用几十个依赖库去实现一两个特性的陷阱;不要引入大量不需要使用的代码.一天结束时,当你没有发现符合你要求的实现时,最好的方式是创建一个属于自己的实现.
优化整体性能
除了上述情况外,还可以优化CPU的性能和用户界面,也会带动内存的优化使用代码混淆去掉不需要的代码
代码混淆工具更少量的RAM映射页.
使用签名工具签名apk文件
如果构建apk后你没有做后续的任何处理(包括根据你的证书进行签名),你必须运行因为像资源这样的东西不会再从apk中进行映射(mmap).
注意:gooleplaystore不接受没有签名的apk
分析你的内存使用情况
使用adbshelldumpsysmeminfo+包名等工具来分析你的应用在各个生命周期的内存使用情况,这个后续博文会有所体现.使用多进程
一种更高级的技术能管理应用中的内存,分离组件技术能把单进程内存划分为多进程内存.该技术一定要谨慎的使用并且大多数的应用都不会跑多进程,因为如果你操作不当反而会浪费更多的内存而不是减少内存.它主要用于后台和前台能各自负责不同业务的应用程序当你构建一个音乐播放器应用并且长时间从一个service中播放音乐时使用多进程处理对你的应用来说更恰当.如果整个应用只有一个进程,当前用户却在另外一个应用或服务中控制播放时,却为了播放音乐而运行着许多不相关的用户界面会造成许多的内存浪费.像这样的应用可以分隔为两个进程:一个进程负责UI
工作,另外一个则在后台服务中运行其它的工作.
在各个应用的manifest文件中为各个组件申明
1 | < service android:name = ".PlaybackService" |
2 | android:process = ":background" /> |
在你决定创建一个新的进程之前必须理解对这样做内存的影响.为了说明每个进程的影响,一个基本空进程会占用大约1.4兆的内存,下面的堆内存信息说明这一点
01 | adbshelldumpsysmeminfocom.example.android.apis:empty |
02 |
03 | **MEMINFO in pid10172[com.example.android.apis:empty]** |
04 | PssPssSharedPrivateSharedPrivateHeapHeapHeap |
05 | TotalCleanDirtyDirtyCleanCleanSizeAllocFree |
06 | ------------------------------------------------------ |
07 | NativeHeap0000001864180063 |
08 | DalvikHeap76405228316005584549985 |
09 | DalvikOther6190378444800 |
10 | Stack28082800 |
11 | Otherdev4012004 |
12 | .sommap287028402129720 |
13 | .apkmmap540001360 |
14 | .dexmmap250148003704148 |
15 | Othermmap8088200 |
16 | Unknown403060038000 |
17 | TOTAL2417148124801392483215274487299148 |
空进程的内存占用是相当显著的,当你的应用加入了许多业务后会增长得更加迅速.下面的例子是使用activity显示一些文字,当前进程的内存使用状况的分析.
01 | **MEMINFO in pid10226[com.example.android.helloactivity]** |
02 | PssPssSharedPrivateSharedPrivateHeapHeapHeap |
03 | TotalCleanDirtyDirtyCleanCleanSizeAllocFree |
04 | ------------------------------------------------------ |
05 | NativeHeap0000003000295148 |
06 | DalvikHeap107404928776005744565886 |
07 | DalvikOther8020361266400 |
08 | Stack28082800 |
09 | Ashmem6016000 |
10 | Otherdev10802410404 |
11 | .sommap216602824182837560 |
12 | .apkmmap480006320 |
13 | .ttfmmap3000240 |
14 | .dexmmap29240056724 |
15 | Othermmap10088680 |
16 | Unknown632041262400 |
17 | TOTAL5169411832403210152887448609134 |
另外,当你的应用超过一个进程时,保持代码的紧凑非常重要,因为现在由相同实现造成的不必要的内存开销会复制到每一个进程中,会造成内存浪费更严重的状况出现.例如,你使用了枚举,不同的进程在内存中都会创建和初始化这些常量.并且你所有的抽象适配器和其它临时的开销也会和前面一样被复制过来.
另外要关心的问题是多进程之间的依赖关系.例如,当应用中运行默认的进程需要为UI进程提供内容,后台进程的代码为进程本身提供内容还要留在内存中为UI运行提供支持,如果你的目标是在一个拥有重量级的UI进程的应用里拥有一个独立运行的后台进程,那么你在UI进程中则不能直接依赖它,而要在UI进程使用service处理它.
相关文章推荐
- 优化Android应用内存的若干方法
- 优化Android应用内存的若干方法
- 优化Android应用内存的若干方法
- 优化Android应用内存的若干方法
- 优化Android应用内存的若干方法
- 优化Android应用内存的若干方法
- 优化Android应用内存的若干方法
- 优化Android应用内存的若干方法
- 优化Android应用内存的若干方法
- 优化Android应用内存的若干方法
- 关于Android应用内存占用查看及优化
- Android应用的性能优化方法
- 关于android应用--内存的优化
- 将HTML5封装成android应用APK文件若干方法
- Android 应用性能优化(二)高效使用内存
- 【转】将HTML5封装成android应用APK 文件若干方法
- 【Android高级】查看手机及应用内存状况的方法
- 将HTML5封装成android应用APK文件若干方法(转)
- android之 BitmapFactory.Options避免内存溢出OOM的优化方法