参考:
http://www.tuicool.com/articles/a2yIRf3
《Android开发艺术探索》
一个应用默认只有一个进程,这个进程(主进程)的名称就是应用的包名,进程是系统分配资源和调度的基本单位,每个进程都有自己独立的资源和内存空间,其它进程不能任意访问当前进程的内存和资源,系统给每个进程分配的内存会有限制。
如果一个进程占用内存超过了这个内存限制,就会报OOM的问题,很多涉及到大图片的频繁操作或者需要读取一大段数据在内存中使用时,很容易报OOM的问题,如果此时在程序中人为地使用GC会严重影响程序运行的流畅性,并且有时候并没有什么卵用,多数时候我们可以在android:minSdkVersion=”11”及以上的应用中,给AndroidManifest.xml的Application标签增加”android:largeHeap=”true”“这句话,请求系统给该应用分配更多可申请的内存:
但是这种做法的弊端有:
有时候并不能彻底解决问题,比如API Level小于11时,或者是应用需要的内存比largeHeap分配的更大的时候;当该应用在后台时,仍然占用着的内存,系统总的内存就那么多,如果每个应用都向系统申请更多的内存,会影响整机运行效率。
为了彻底地解决应用内存的问题,Android引入了多进程的概念,它允许在同一个应用内,为了分担主进程的压力,将占用内存的某些页面单独开一个进程,比如Flash、视频播放页面,频繁绘制的页面等。Android多进程使用很简单,只需要在AndroidManifest.xml的声明四大组件的标签中增加”android:process”属性即可,process分私有进程和全局进程,私有进程的名称前面有冒号,全局进程没有,like this:
使用多进程会遇到的一些问题:
断点调试
调试就是跟踪程序运行过程中的堆栈信息,正如前面所讲,每个进程都有自己独立的资源和内存空间,每个进程的堆栈信息也是独立的,如果要在不同的进程间调试,是实现不了的,不过可以通过如下两种方式进行调试:调试的时候去掉AndroidManifest.xml文件中Activity的android:process标签,这样保证调试状态下是在同一进程中,堆栈信息是连贯的,在调试完成后记得复原该属性;通过打印进行调试,但这种效率比较低。
内存共享:
不同进程之间内存不能共享,最大的弊端是他们之间通信麻烦,不能将公用数据放在Application中,堆栈信息、文件操作也是独立的,如果他们之间传递的数据不大并且是可序列化的,可以考虑通过Bundle传递, 如果数据量较大,则需要通过AIDL或者文件操作来实现。
结语
通过多进程可以分担应用内主进程的压力,但这是下下策,最好的解决方案还是要做好性能优化。
要想知道如何使用多进程,先要知道Android里的多进程概念。一般情况下,一个应用程序就是一个进程,这个进程名称就是应用程序包名。我们知道进程是系统分配资源和调度的基本单位,所以每个进程都有自己独立的资源和内存空间,别的进程是不能任意访问其他进程的内存和资源的。那如何让自己的应用拥有多个进程?很简单,我们的四大组件在AndroidManifest文件中注册的时候,有个属性是android:process,
1.这里可以指定组件的所处的进程。默认就是应用的主进程。指定为别的进程之后,系统在启动这个组件的时候,就先创建(如果还没创建的话)这个进程,然后再创建该组件。你可以重载Application类的onCreate方法,打印出它的进程名称,就可以清楚的看见了。再设置android:process属性时候,有个地方需要注意:如果是android:process=":deamon",以:开头的名字,则表示这是一个应用程序的私有进程,否则它是一个全局进程。私有进程的进程名称是会在冒号前自动加上包名,而全局进程则不会。一般我们都是有私有进程,很少使用全局进程。他们的具体区别不知道有没有谁能补充一下。
2.使用多进程显而易见的好处就是分担主进程的内存压力。我们的应用越做越大,内存越来越多,将一些独立的组件放到不同的进程,它就不占用主进程的内存空间了。当然还有其他好处,有心人会发现Android后台进程里有很多应用是多个进程的,因为它们要常驻后台,特别是即时通讯或者社交应用,不过现在多进程已经被用烂了。典型用法是在启动一个不可见的轻量级私有进程,在后台收发消息,或者做一些耗时的事情,或者开机启动这个进程,然后做监听等。还有就是防止主进程被杀守护进程,守护进程和主进程之间相互监视,有一方被杀就重新启动它。应该还有还有其他好处,这里就不多说了。
3.坏处的话,多占用了系统的空间,大家都这么用的话系统内存很容易占满而导致卡顿。消耗用户的电量。应用程序架构会变复杂,应为要处理多进程之间的通信。这里又是另外一个问题了。
关于Process的使用最常见的例子是Service。针对Service进行使用需要考虑两种情况
情况1.应用中有Activity部分有会使用较多的UI,占用较多的内存资源,并且要求Activity退到后台情况下要求Service在后台运行。因为Android本身有Low Memory Killer这套机制,在系统内存吃紧的情况下会去会砍掉内存占用较多(一般是OOM_ADJ值较大的Process),此时因为有Service在后台运行,所以会降低OOM_ADJ,Low Memory Killer在砍Process的时候就不容易将此部分内存回收。此时可以考虑将Service从应用进程中分离出来,这样Low Memory Killer在回收内存时会将因为Activity部分占用的内存较大,OOM_ADJ较大,优先将其砍掉释放内存。同时保证Service正常运行。
情况2.在系统中有很多有共性的Service,同时应用中Activity显示部分的UI不多或者没有Activity.可以将这些Service合并成同一个进程。因为android没启动一个进行,在zygote fork阶段会预载于一部分资源占用内存(具体几M记不清楚了),通过将Service合并,可以节省这部分开销。