4.3深入理解Android卷I---深入理解zygote---拓展思考

虽然邓老师的书写的很细致,但是对应的Android版本过低,所以后期有时间我这里会查阅资料,对这部分内容尝试进行更新。
4.5.1 虚拟机heapsize的限制
在分析Zygote创建虚拟机的时候,我们说过系统默认设置的Java虚拟机堆栈最大为16MB,这个值对于需要使用较大内存的程序(例如图片处理程序)来说还远远不够。当然,可以修改这个默认值,例如我的HTC G7就将其修改为32MB了,但是这个改动是全局性的,也就是所有的Java程序都会是这个32MB。我们能动态配置这个值吗?例如:
· 设置一个配置文件,每个进程启动的时候根据配置文件的参数来设置堆大小。
不过正如前面所说,我的这一美好愿望最终破灭了,原因只有一个:
· Zygote是通过fork来创建子进程的,Zygote本身设置的信息会被子进程全部继承,例如Zygote设置的堆栈为16MB,那么它的子进程也是用这个16MB。
关于这个问题,邓老师目前想到了两个解决方案:
· 为Dalivk增加一个函数,这个函数允许动态调整最大堆的大小。
· Zygote通过fork子进程后,调用exec家族的函数来加载另外一个映像,该映像对应的程序会重新创建虚拟机,重新注册JNI函数,也就是模拟Zygote创世界中前两天的工作,最后调用android.app.ActivityThread的main函数。这种方式应该是可行的,但难度较大,而且会影响运行速度。

4.5.2 开机速度优化
Android开机速度慢这一现象一直受人诟病,Google好像也没有要做这方面优化的意向,那么,在实际工作中又在哪些地方可以做一些优化呢?根据我目前所掌握的资料分析,有三个地方耗时比较长:
· ZygoteInit的main函数中preloadClasses加载的那一千多个类。
· 开机启动时,会对系统内所有的apk文件扫描并收集信息,这个动作耗费的时间非常长。
· SystemServer创建的那些Service,会占用不少时间。
这里讨论第一个问题,如何减少preloadClasses的时间呢?其实,这个函数是可以去掉的,因为系统最终还是会在使用这些类时去加载,但这样就破坏了Android采用fork机制来创建Java进程的本意,而fork机制的好处则是显而易见的:
· Zygote预加载的这些class,在fork子进程时,仅需做一个复制即可。这样就节约了子进程的启动时间。
· 根据fork的copy-on-write机制,有些类如果不做改变,甚至连复制都不用,它们会直接和父进程共享数据。这样就会省去不少内存的占用。
开机速度优化是一项比较复杂的研究,目前有人使用Berkeley Lab Checkpoint/Restart(BLCR)技术来提升开机速度。这一技术的构想其实挺简单,就是对当前系统做一个快照,保存到一个文件中,当系统重启时,直接根据文件的快照信息来恢复重启之前的状态。当然想法很简单,实现却是很复杂的,这里对此不做进一步的讨论,还需自行展开深入的思考和研究
邓老师在VMWare虚拟机上使用过类似的技术,它叫Snapshort。开机速度的问题我更希望Google自己能加以重视并推动它的解决。
4.5.3 Watchdog分析
Watch Dog的中文意思是“看门狗”。其最初存在的意义是因为早期嵌入式设备上的程序经常“跑飞”(比如说电磁干扰等),所以专门有个硬件看门狗,每隔一段时间,看门狗就去检查一下某个参数是不是被设置了,如果发现该参数没有被设置,则判断为系统出错,然后就会强制重启。
软件层面上Android对SystemServer对参数是否被设置也很谨慎,专门为它增加了一条看门狗,用来监听几个重要Service的门,一旦发现Service出了问题,就会杀掉system_server,这样就使zygote随其一起自杀,最后导致重启Java世界。
我们先把SystemServe使用Watchdog的调用流程总结一下,然后以这个为切入点来分析Watchdog。SS和Watchdog的交互流程可以总结为以下三个步骤:
· Watchdog. getInstance().init()
· Watchdog.getInstance().start()
· Watchdog. getInstance().addMonitor()
1. 创建和初始化Watchdog
Watchdog. getInstance().init()方法,首先通过单例模式构建实例,由于Watchdog从线程类派生,所以它会在单独的一个线程中执行,构造一个Handler并在handleMessage函数中处理消息。看门狗诞生后,继续看init函数中为变量赋值,然后对它们进行监听。
2. 看门狗跑起来
SystemServer调用Watchdog的start函数,将导致Watchdog的run在另外一个线程中被执行(mHandler的消息处理是在另外一个线程上)。在run方法中会给那个线程的消息队列发条消息,请求Watchdog检查Service是否工作正常。run函数还是比较简单的,就是:
· 隔一段时间给另外一个线程发送一条MONITOR消息,那个线程将检查各个Service的健康情况。而看门狗会等待检查结果,如果第二次还没有返回结果,那么它会杀掉SS。
3. 列队检查
这么多Service,一共有三个Service是需要交给Watchdog检查的:
· ActivityManagerService
· PowerManagerService
· WindowManagerService
要想支持看门狗的检查,就需要这些Service实现monitor接口,然后Watchdog就会调用它们的monitor函数进行检查了。检查的地方是在HeartbeatHandler类的handleMessage中。Service在构造函数中把自己加入Watchdog的检查队列,通过查看Watchdog实现的monitor函数可知:monitor原来检查的就是这些Service是不是发生死锁了。故可知Watchdog最怕系统服务死锁了,对于这种情况也只能采取杀系统的办法了。

4.6 本章小结
本章对Zygote进程做了较为深入的分析,Zygote的主要工作是开创Java世界,本章介绍了它创世纪的七大步骤。另外,本章还分析了Zygote的“嫡长子”——System_server进程,这个进程是Java世界中的系统Service的驻留地,所以它非常重要。对于System_server进程,本章重点关注的是它的创建和初始化过程。此外,我们还分析了一个Activity所属进程的创建过程,原来这个进程是由ActivityManagerService发送请求给Zygote,最后由Zygote通过fork的方式创建的。
在本章拓展部分,分析了Dalvik虚拟机对heap大小的设置及其可能的修改方法,另外还探讨了Android系统开机速度的问题。最后,本章还分析了System_server中Watchdog的工作流程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值