上海天局信息技术有限责任公司

网站首页 > 天局论坛 > Android > App

Android中App可分配内存的大小

2017-12-08 14:10:50 上海天局信息技术有限责任公司 已读

Android应用程序的默认最大内存值为16M,如果应用程序优化程度不够或者其它原因可能会出现内存溢出

dumpsys meminfo 3067   3067是calender进程的PID。


root@sabresd_6dq:/ # dumpsys meminfo 3067                                      
Applications Memory Usage (kB):
Uptime: 6350920 Realtime: 6350907

** MEMINFO in pid 3067 [com.android.calendar] **
                   Pss  Private  Private  Swapped     Heap     Heap     Heap
                 Total    Dirty    Clean    Dirty     Size    Alloc     Free
                ------   ------   ------   ------   ------   ------   ------
  Native Heap       22       20        0        0     1872     1850       21
  Dalvik Heap      854      624        0        0     3264     2919      345
  Dalvik Other     1003      716        0        0                           
  Stack       20       20        0        0                           
  Other dev        4        0        4        0                           
  .so mmap      445      236        0        0                           
  .apk mmap      504        0      464        0                           
  .dex mmap      904       12      464        0                           
  Other mmap       12        8        0        0                           
  Unknown      616      576        0        0                           
  TOTAL     4384     2212      932        0     5136     4769      366
 
 Objects
     Views:        0         ViewRootImpl:        0
    AppContexts:        4           Activities:        0
    Assets:        2        AssetManagers:        2
    Local Binders:       10        Proxy Binders:       11
    Death Recipients:        0
    OpenSSL Sockets:        0
 
 SQL
    MEMORY_USED:        0
    PAGECACHE_OVERFLOW:        0          MALLOC_SIZE:        0


Naitve Heap Size: 从mallinfo usmblks获得,代表最大总共分配空间

Native Heap Alloc: 从mallinfo uorblks获得,总共分配空间

Native Heap Free: 从mallinfo fordblks获得,代表总共剩余空间 

Native Heap Size 约等于Native Heap Alloc + Native Heap Free

mallinfo是一个C库, mallinfo 函数提供了各种各样的通过C的malloc()函数分配的内存的统计信息。

Dalvik Heap Size:从Runtime totalMemory()获得,Dalvik Heap总共的内存大小。

Dalvik Heap Alloc: Runtime totalMemory()-freeMemory() ,Dalvik Heap分配的内存大小。

Dalvik Heap Free:从Runtime freeMemory()获得,Dalvik Heap剩余的内存大小。

Dalvik Heap Size 约等于Dalvik  Heap Alloc + Dalvik  Heap Free

OtherPss, include Cursor,Ashmem, Other Dev, .so mmap, .jar mmap, .apk mmap, .ttf mmap, .dex mmap, Other mmap, Unkown统计信息都可以在process的smap文件看到。

Objects and SQL 信息都是从Android Debug信息中获得。

其他类型               smap 路径名称          描述

Cursor                  /dev/ashmem/Cursor  Cursor消耗的内存(KB)

Ashmem               /dev/ashmem            匿名共享内存用来提供共享内存通过分配一个多个进程

                                                         可以共享的带名称的内存块

Other dev             /dev/                        内部driver占用的在 “Other dev”                                                 

.so mmap             .so                            C 库代码占用的内存

.jar mmap            .jar                           Java 文件代码占用的内存

.apk mmap           .apk                           apk代码占用的内存

.ttf mmap              .ttf                           ttf 文件代码占用的内存

.dex mmap             .dex                         Dex 文件代码占用的内存

Other mmap                                          其他文件占用的内存


以下转载一篇文章

众所周知,在写 android 程序的时候,很容易出现 OOM ,而出现的时机大多数是由 Bitmap decode 引发的:


1

ERROR/AndroidRuntime(16350): java.lang.OutOfMemoryError: bitmap size exceeds VM budget

      我们知道,android程序内存一般限制在16M,当然也有24M的,而android程序内存被分为2部分:native和dalvik:

dalvik就是我们平常说的java堆,我们创建的对象是在这里面分配的,而bitmap是直接在native上分配的,对于内存的限制是native+dalvik不能超过最大限制。

注:

一旦内存分配给Java后,以后这块内存纵然开释后,也只能给Java的施用,这个估计跟java虚拟机里把内存分成好几块进行缓存的原因有关,反正C就别想用到这块的内存了,所以要是Java突然占用了一个大块内存,纵然很快开释了: 

C能施用的内存 = 16M - Java某一瞬间占用的最大内存。 

Bitmap的生成是通过malloc进行内存分配的,占用的是C的内存,这个也就说明了,上面所说的的4MBitmap无法生成的原因,因为在13MJava用过后,剩下C能用的只有3M了。

      用以下命令可以查看程序的内存使用情况:


adb shell dumpsysmeminfopackagename orpid程序的包名或者进程id


图片关键词

    其中size是需要的内存,而allocated是分配了的内存,对应的2列分别是native和dalvik,当总数也就是total这一列超过单个程序内存的最大限制时,OOM就很有可能会出现了。

       多数时候,发生OOM 都是在做一些跟图片相关的操作,以下提出一些建议尽量可以减少这种情况的发生:


1

.decode bitmap 的时候,尽量配置下Options,例如:inSameSize

2

.Bitmap使用完以后,调用 bitmap.recycle()来释放内存


 


3

.如果应用是基于图片的应用,尽量采用LazyLoad和DymanicRecycle

4.decode bitmap 的时候,将decode代码 try catch 出来,catch oom error,避免程序crash,可以在catch里面做一些释放内存操作


关于Android的Native内存和Dalvik内存

1.   Dalvik内存

每一个Android应用在底层都会对应一个独立的Dalvik虚拟机实例,其代码在虚拟机的解释下得以执行。

很多人认为Dalvik虚拟机是一个Java虚拟机,因为Android的编程语言恰恰就是Java语言。但是这种说法并不准确,因为 Dalvik虚拟机并不是按照Java虚拟机的规范来实现的,两者并不兼容;

同时还要两个明显的不同:

  1.Java虚拟机运行的是Java字节码,而Dalvik虚拟机运行的则是其专有的文件格式DEX(Dalvik Executable)。

2.在Java SE程序中的Java类会被编译成一个或者多个字节码文件(.class)然后打包到JAR文件,而后Java虚拟机会从相应的CLASS文件和JAR文件中获取相应的字节码;Android应用虽然也是使用Java语言进行编程,但是在编译成CLASS文件后,还会通过一个工具(dx)将应用所有的 CLASS文件转换成一个DEX文件,而后Dalvik虚拟机会从其中读取指令和数据。

Dalvik虚拟机的简介:

Dalvik虚拟机主要是完成对象生命周期的管理,堆栈的管理,线程管理,安全和异常的管理,以及垃圾回收等等重要功能。

Dalvik虚拟机的主要特征Dalvik虚拟机非常适合在移动终端上使用,相对于在桌面系统和服务器系统运行的虚拟机而言,它不需要很快的CPU速度和大量的内存空间。

Dalvik虚拟机有如下几个主要特征:

1.专有的DEX文件格式

DEXDalvik虚拟机专用的文件格式,而问什么弃用已有的字节码文件(CLASS文件)而采用新的格式呢?一个应用中会定义很多类,编译完成后即会有很多相应的CLASS文件,CLASS文件间会有不少冗余的信息;而DEX文件格式会把所有的 CLASS文件内容整合到一个文件中。这样,除了减少整体的文件尺寸,I/O操作,也提高了类的查找速度。

2.增加了新的操作码的支

3.文件结构尽量简洁,使用等长的指令,借以提高解析速度

4.尽量扩大只读结构的大小,借以提高跨进程的数据共享

2.   Native内存

如何修改Android应用程序的默认最大内存值

Android应用程序的默认最大内存值为16M,有些应用程序可能会出现内存溢出,譬如ERROR/AndroidRuntime(264):java.lang.OutOfMemoryError: bitmap size exceeds VM budget

除了要检查修正代码之外,还可以考虑修改Android应用程序的默认最大内存值。

修改应用程序的默认最大内存有2种方法:

1、修改代码,适用于自己编译烧机:

当应用程序分配内存时,会调用到dalvik/vm/alloc/HeapSource.c中的dvmTrackExternalAllocation()方法,继而调用到externalAllocPossible()方法,该方法要求当前堆已使用的大小(由currentHeapSize和hs->externalBytesAllocated构成)加上我们需要再次分配的内存大小不能超过堆的最大内存值,如果超过就会报错。 

有两个地方决定了一个堆的最大内存: 

1)dalvik/vm/Init.c中的 

gDvm.heapSizeMax = 16 * 1024 * 1024;    // Spec says 75%physical mem 

2)frameworks/base/core/jni/AndroidRuntime.cpp中的 

property_get("dalvik.vm.heapsize", heapsizeOptsBuf+4,"16m"); 

因此解决办法就是将以上2点中默认的16M改大一点,譬如32M。

2、修改配置文件,适用于烧机后的版本。

修改或添加/system/build.prop中的配置项:

dalvik.vm.heapstartsize=20m

dalvik.vm.heapgrowthlimit=200m

dalvik.vm.heapsize=320m


=====================另一篇文章 如何优化android内存==============================

原文地址:

http://my.oschina.net/chaselinfo/blog/198172

使用保守的Service

如果你的应用需要使用 service 在后台执行业务功能, 除非是一直在进行活动的工作(比如每隔几秒向服务器端请求数据之类)否则不要让它一直保持在后台运行. 并且, 当你的 service 执行完成但是停止失败时要小心 service 导致的内存泄露问题.

当你启动 service 时, 系统总是优先保持服务的运行. 这会导致内存应用效率非常低, 因为被该服务使用的内存不能做其它事情. 也会减少系统一直保持的LRU缓存处理数目, 使不同的app切换效率降低. 当前所有 service 的运行会导致内存不够不能维持正常系统的运行时, 系统会发生卡顿的现象严重时能导致系统不断重启.

最好的方式是使用 IntentSevice 控制 service 的生命周期, 当使用 intent 开始任务后, 该 service 执行完所有的工作时会自动停止.

在android应用中当不需要使用常驻 service 执行业务功能而去使用一个常驻 service 是最糟糕的内存管理方式之一. 所以不要贪婪的使用 service 使你的应用一直运行状态. 这样不仅使你因为内存的限制提高了应用运行的风险, 也会导致用户发现这些异常行为后而卸载应用.


当视图变为隐藏状态后释放内存

当用户跳转到不同的应用并且你的视图不再显示时, 你应该释放应用视图所占的资源. 这时释放所占用的资源能显著的提高系统的缓存处理容量, 并且对用户的体验质量有直接的影响.

当实现当前 Activity 类的 onTrimMemory() 回调方法后, 用户离开视图时会得到通知. 使用该方法可以监听 TRIM_MEMORY_UI_HIDDEN 级别, 当你的视图元素从父视图中处于隐藏状态时释放视图所占用的资源.

注意只有当你应用的所有视图元素变为隐藏状态时你的应用才能收到 onTrimMemory() 回调方法的 TRIM_MEMORY_UI_HIDDEN . 这个和 onStop() 回调方法不同, 该方法只有当 Activity 的实例变为隐藏状态, 或者有用户移动到应用中的另外的 activity 才会引发. 所以说你虽然实现了 onStop() 去释放 activity 的资源例如网络连接或者未注册的广播接收者, 但是应该直到你收到 onTrimMemory(TRIM_MEMORY_UI_HIDDEN)才去释放视图资源否则不应该释放视图所占用的资源. 这里可以确定的是如果用户通过后退键从另外的 activity 进入到你的应用中, 视图资源会一直处于可用的状态可以用来快速的恢复 activity.


内存资源紧张时释放内存

在应用生命周期的任何阶段 onTrimMemory() 回调方法都可以告诉你设备的内存越来越低的情况, 你可以根据该方法推送的内存紧张级别来释放资源.

  • TRIM_MEMORY_RUNNING_CRITICAL

应用处于运行状态并且不会被杀掉, 设备使用的内存比较低, 系统级会杀掉一些其它的缓存应用.

  • TRIM_MEMORY_RUNNING_LOW

应用处于运行状态并且不会被杀掉, 设备可以使用的内存非常低, 可以把不用的资源释放一些提高性能(会直接影响程序的性能)

  • TRIM_MEMORY_RUNNING_CRITICAL

应用处于运行状态但是系统已经把大多数缓存应用杀掉了, 你必须释放掉不是非常关键的资源, 如果系统不能回收足够的运行内存, 系统会清除所有缓存应用并且会把正在活动的应用杀掉.

还有, 当你的应用被系统正缓存时, 通过 onTrimMemory() 回调方法可以收到以下几个内存级别:

  • TRIM_MEMORY_BACKGROUND

系统处于低内存的运行状态中并且你的应用处于缓存应用列表的初级阶段.  虽然你的应用不会处于被杀的高风险中, 但是系统已经开始清除缓存列表中的其它应用, 所以你必须释放资源使你的应用继续存留在列表中以便用户再次回到你的应用时能快速恢复进行使用.

  • TRIM_MEMORY_MODERATE

系统处于低内存的运行状态中并且你的应用处于缓存应用列表的中级阶段. 如果系运行内存收到限制, 你的应用有被杀掉的风险.

  • TRIM_MEMORY_COMPLETE

系统处于低内存的运行状态中如果系统现在没有内存回收你的应用将会第一个被杀掉. 你必须释放掉所有非关键的资源从而恢复应用的状态.

因为 onTrimMemory() 是在级别14的android api中加入的, 所以低版本的要使用 onLowMemory() 方法, 该方法大致相当于 TRIM_MEMORY_COMPLETE 事件.

注意: 当系统开始清除缓存应用列表中的应用时, 虽然系统的主要工作机制是自下而上, 但是也会通过杀掉消费大内存的应用从而使系统获得更多的内存, 所以在缓存应用列表中消耗更少的内存将会有更大的机会留存下来以便用户再次使用时进行快速恢复.

检查可以使用多大的内存

前面提到, 不同的android设备系统拥有的运行内存各自都不同, 从而不同的应用堆内存的限制大小也不一样. 你可以通过调用 ActivityManager 中的 getMemoryClass() 函数可以通过以兆为单位获取当前应用可用的内存大小, 如果你想获取超过最大限度的内存则会发生 OutOfMemoryError .

有一个特别的情况, 可以在 manifest 文件中的 <application> 标签中设置 largeHeap 属性的值为 "true"时, 当前应用就可以获取到系统分配的最大堆内存. 如果你设置了该值, 可以通过 ActivityManager 的 getLargeMemoryClass() 函数获取最大的堆内存.

然后, 只有一小部分应用需要消耗大量堆内存(比如大照片编辑应用). 从来不需要使用大量内存仅仅是因为你已经消耗了大量的内存并且必须快速修复它, 你必须使用它是因为你恰好知道所有的内存已经被分配完了而你必须要保留当前应用不会被清除掉. 甚至当你的应用需要消耗大量内存时, 你应该尽可能的避免这种需求. 使用大量内存后, 当你切换不同的应用或者执行其它类似的操作时, 因为长时间的内存回收会导致系统的性能下降从而渐渐的会损害整个系统的用户体验.

另外, 大内存不是所有的设备都相同.  当跑在有运行内存限制的设备上时, 大内存和正常的堆内存是一样的.  所以如果你需要大内存, 你就要调用 getMemoryClass() 函数查看正常的堆内存的大小并且尽可能使内存使用情况维护在正常堆内存之下.

避免在 bitmaps 中浪费内存

当你加载 bitmap 时, 需要根据分辨率来保持它的内存时最大为当前设备的分辨率, 如果下载下来的原图为高分辨率则要拉伸它. 要小心bitmap的分辨率增加后所占用的内存也要进行相应的增加, 因为它是根据x和y的大小来增加内存占用的.

注意: 在 Android 2.3.x(api level 10)以下, 无论图片的分辨率多大 bitmap 对象在内存中始终显示相同大小, 实际的像素数据被存储在底层 native 的内存中(c++内存). 因为内存分析工具无法跟踪 native 的内存状态所有调试 bitmap 内存分配变得非常困难. 然而, 从 Android 3.0(api level 11)开始, bitmap 对象的内存数据开始在应用程序所在Dalvik虚拟机堆内存中进行分配, 提高了回收机率和调试的可能性. 如果你在老版本中发现 bitmap 对象占用的内存大小始终一样时, 切换设备到系统3.0或以上来进行调试.

使用优化后的数据容器

利用 Android 框架优化后的数据容器, 比如 SparseArraySparseBooleanArray 和 LongSparseArray. 传统的 HashMap 在内存上的实现十分的低效因为它需要为 map 中每一项在内存中建立映射关系. 另外, SparseArray类非常高效因为它避免系统中需要自动封箱(autobox)的key和有些值.

知道内存的开销

在你设计应用各个阶段都要很谨慎的考虑所使用的语言和库带来的内存上的成本和开销. 通常情况下, 表面上看起来无害的会带来巨大的开销,  下面在例子说明:

  • 当枚举(enum)成为静态常量时超过正常两倍以上的内存开销, 在 android 中你需要严格避免使用枚举
  • java 中的每个类(包含匿名内部类)大约使用500个字节
  • 每个类实例在运行内存(RAM)中占用12到16个字节
  • 在 hashmap 中放入单项数据时, 需要为额外的其它项分配内存, 总共占用32个字节

使用很多的不必要类和对象时, 增加了分析堆内存问题的复杂度.

当心抽象代码

通常来说, 使用简单的抽象是一种好的编程习惯, 因为一定程度上的抽象可以提供代码的伸缩性和可维护性. 然而抽象会带来非常显著的开销: 需要执行更多的代码, 需要更长时间和更多的运行内存把代码映射到内存中, 所以如果抽象没有带来显著的效果就尽量避免.

使用纳米 Protocol buffers 作为序列化数据

Protocol Buffers 是 Google 公司开发的一种数据描述语言,类似于XML能够将结构化数据序列化. 但是它更小, 更快, 更简单. 如果你决定使用它作为你的数据, 你必须在你的客户端代码中一直使用纳米 protocol buffer, 因为正常的 protocol buffer 会产生极其冗余的代码, 在你的应用生会引起很多问题: 增加了使用的内存, 增加了apk文件的大小, 执行速度较慢以及会快速的把一些限定符号打入 dex 包中.

尽量避免使用依赖注入框架

使用像 Guice 和 RoboGuice 依赖注入框架会有很大的吸引力, 因为它使我们可以写一些更简单的代码和提供自适应的环境用来进行有用的测试和进行其它配置的更改. 然而这些框架通过注解的方式扫描你的代码来执行一系列的初始化, 但是这些也会把一些我们不需要的大量的代码映射到内存中. 被映射后的数据会被分配到干净的内存中, 放入到内存中后很长一段时间都不会使用, 这样造成了内存大量的浪费.

谨慎使用外部依赖库

许多的外部依赖库往往不是在移动环境下写出来的, 这样当在移动使用中使用这些库时就会非常低效. 所以当你决定使用一个外部库时, 你就要承担为优化为移动应用外部库带来的移植问题和维护负担. 在项目计划前期就要分析该类库的授权条件, 代码量, 内存的占用再来决定是否使用该库.

甚至据说专门设计用于 android 的库也有潜在的风险, 因为每个库做的事情都不一样. 例如, 一个库可能使用的是 nano protobuf 另外一个库使用的是 micro protobuf, 现在在你的应用中有两个不同 protobuf 的实现. 这将会有不同的日志, 分析, 图片加载框架, 缓存, 等所有你不可预知的事情的发生. Proguard 不会保存你的这些, 因为所有低级别的 api 依赖需要你依赖的库里所包含的特征. 当你使用从外部库继承的 activity 时尤其会成为一个问题(因为这往往产生大量的依赖). 库要使用反射(这是常见的因为你要花许多时间去调整ProGuard使它工作)等.

也要小心不要陷入使用几十个依赖库去实现一两个特性的陷阱; 不要引入大量不需要使用的代码. 一天结束时, 当你没有发现符合你要求的实现时, 最好的方式是创建一个属于自己的实现.

优化整体性能

除了上述情况外, 还可以优化CPU的性能和用户界面, 也会带动内存的优化

使用代码混淆去掉不需要的代码

代码混淆工具 ProGuard 通过去除没有用的代码和通过语义模糊来重命名类, 字段和方法来缩小, 优化和混淆你的代码. 使用它能使你的代码更简洁, 更少量的RAM映射页.

使用签名工具签名apk文件

如果构建apk后你没有做后续的任何处理(包括根据你的证书进行签名), 你必须运行 zipalign 工具为你的apk重新签名, 如果不这样做会导致你的应用使用更多的内存, 因为像资源这样的东西不会再从apk中进行映射(mmap).

注意:goole play store 不接受没有签名的apk

分析你的内存使用情况

使用adb shell dumpsys meminfo +包名 等工具来分析你的应用在各个生命周期的内存使用情况, 这个后续博文会有所体现.

使用多进程

一种更高级的技术能管理应用中的内存, 分离组件技术能把单进程内存划分为多进程内存. 该技术一定要谨慎的使用并且大多数的应用都不会跑多进程, 因为如果你操作不当反而会浪费更多的内存而不是减少内存. 它主要用于后台和前台能各自负责不同业务的应用程序

当你构建一个音乐播放器应用并且长时间从一个 service 中播放音乐时使用多进程处理对你的应用来说更恰当. 如果整个应用只有一个进程, 当前用户却在另外一个应用或服务中控制播放时, 却为了播放音乐而运行着许多不相关的用户界面会造成许多的内存浪费. 像这样的应用可以分隔为两个进程:一个进程负责 UI 工作, 另外一个则在后台服务中运行其它的工作.

在各个应用的 manifest 文件中为各个组件申明 android:process 属性就可以分隔为不同的进程.例如你可以指定你一运行的服务从主进程中分隔成一个新的进程来并取名为"background"(当然名字可以任意取).

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

进程名字必须以冒号开头":"以确保该进程属于你应用中的私有进程.

在你决定创建一个新的进程之前必须理解对这样做内存的影响. 为了说明每个进程的影响, 一个基本空进程会占用大约1.4兆的内存, 下面的堆内存信息说明这一点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
adb shell dumpsys meminfo com.example.android.apis:empty
 
** MEMINFO in pid 10172 [com.example.android.apis:empty] **
                Pss     Pss  Shared Private  Shared Private    Heap    Heap    Heap
              Total   Clean   Dirty   Dirty   Clean   Clean    Size   Alloc    Free
             ------  ------  ------  ------  ------  ------  ------  ------  ------
  Native Heap     0       0       0       0       0       0    1864    1800      63
  Dalvik Heap   764       0    5228     316       0       0    5584    5499      85
 Dalvik Other   619       0    3784     448       0       0
        Stack    28       0       8      28       0       0
    Other dev     4       0      12       0       0       4
     .so mmap   287       0    2840     212     972       0
    .apk mmap    54       0       0       0     136       0
    .dex mmap   250     148       0       0    3704     148
   Other mmap     8       0       8       8      20       0
      Unknown   403       0     600     380       0       0
        TOTAL  2417     148   12480    1392    4832     152    7448    7299     148

注意: 上面关键的数据是 private dirty 和 private clean 两项, 第一项主要使用了大约是1.4兆的非分页内存(分布在Dalvik heap, native分配, book-keeping, 和库的加载), 另外执行业务代码使用150kb的内存.

空进程的内存占用是相当显著的, 当你的应用加入了许多业务后会增长得更加迅速. 下面的例子是使用activity显示一些文字, 当前进程的内存使用状况的分析.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
** MEMINFO in pid 10226 [com.example.android.helloactivity] **
                Pss     Pss  Shared Private  Shared Private    Heap    Heap    Heap
              Total   Clean   Dirty   Dirty   Clean   Clean    Size   Alloc    Free
             ------  ------  ------  ------  ------  ------  ------  ------  ------
  Native Heap     0       0       0       0       0       0    3000    2951      48
  Dalvik Heap  1074       0    4928     776       0       0    5744    5658      86
 Dalvik Other   802       0    3612     664       0       0
        Stack    28       0       8      28       0       0
       Ashmem     6       0      16       0       0       0
    Other dev   108       0      24     104       0       4
     .so mmap  2166       0    2824    1828    3756       0
    .apk mmap    48       0       0       0     632       0
    .ttf mmap     3       0       0       0      24       0
    .dex mmap   292       4       0       0    5672       4
   Other mmap    10       0       8       8      68       0
      Unknown   632       0     412     624       0       0
        TOTAL  5169       4   11832    4032   10152       8    8744    8609     134

这个比上面多花费了3倍的内存, 只是在 界面 上显示一些简单的文字, 用了大约4兆. 从这里可以得出一个很重要的结论:如果你的想在应用中使用多进程, 只能有一个进程来负责 UI 的工作, 在其它进程中不能出现任何 UI的工作, 否则会迅速提高内存的使用率(尤其当你加载 bitmap 资源和其它资源时). 一旦加入了UI的绘制工作就不可能会减少内存的使用了.

另外, 当你的应用超过一个进程时, 保持代码的紧凑非常重要, 因为现在由相同实现造成的不必要的内存开销会复制到每一个进程中, 会造成内存浪费更严重的状况出现. 例如, 你使用了枚举, 不同的进程在内存中都会创建和初始化这些常量.并且你所有的抽象适配器和其它临时的开销也会和前面一样被复制过来.

另外要关心的问题是多进程之间的依赖关系. 例如, 当应用中运行默认的进程需要为UI进程提供内容, 后台进程的代码为进程本身提供内容还要留在内存中为UI运行提供支持, 如果你的目标是在一个拥有重量级的UI进程的应用里拥有一个独立运行的后台进程, 那么你在UI进程中则不能直接依赖它, 而要在UI进程使用 service 处理它.


Powered by MetInfo 5.3.17 ©2008-2022 www.metinfo.cn