理解Android:Zygote和DalvikVM

63

我正在尝试了解Android应用程序的启动方式。问题是Zygote为什么要分叉一个新的Dalvik虚拟机?而且为什么不能在同一个Dalvik虚拟机中运行多个应用程序?

5个回答

168

问:Zygote如何精确地分叉Dalvik VM?

简短回答: Zygote进程在系统启动时冷启动Java VM。然后监听一个套接字以获取传入的命令。其他进程(例如ActivityManagerService)在需要应用程序的新进程时向此套接字写入命令。这些命令由Zygote进程读取,必要时调用fork()。子进程获得一个预热的VM来运行。这就是Zygote如何分叉Dalvik VM。

详细回答:内核加载后,解析init.rc并启动本地服务。然后运行/system/bin/app_process。最终调用AndroidRuntime.start(),将参数com.android.internal.os.ZygoteInitstart-system-server传递给它。

AndroidRuntime.start()启动Java虚拟机,然后调用ZygoteInit.main(),将参数start-system-server传递给它。

ZygoteInit.main()注册Zygote套接字(Zygote进程侦听传入命令的套接字,并在接收到新命令时按请求生成新进程)。然后,它预加载许多类(如frameworks/base/preloaded-classes中列出的类,在Android 8.0中超过4500个),以及所有系统范围的资源,如可绘制对象、xml等。然后它调用startSystemServer()com.android.server.SystemServer分叉一个新进程。这个分支是特殊的,不像Zygote代表请求进程执行的常规分支那样执行。

在fork SystemServer之后,会调用runSelectLoopMode()函数。这是一个while(true)循环,它与Zygote套接字建立了一个ZygoteConnection并等待命令。当接收到命令时,ZygoteConnection.runOnce()被调用。

ZygoteConnection.runOnce()然后调用Zygote.forkAndSpecialize(),然后调用本地函数来进行实际的fork。因此,就像SystemServer的情况一样,创建了一个子进程,该进程继承了一个预热的Dalvik VM。

问:为什么不能在同一个Dalvik VM中运行多个应用程序?

据我所知,这是一个设计决策。Android开发人员只是决定为每个进程fork一个新的VM,以通过沙箱实现安全性。


关于“为什么不可能在同一个Dalvik VM中运行多个应用程序?”这个问题,当您要求组件在同一进程中运行时,是否会发生这种情况,例如使用android:process="<shared>"。此外,还可以通过使用android:sharedUserId="<id>"来实现。 - Igor Čordaš
"AndroidRuntime.start() 启动了 Java VM",你是不是指的 Dalvik VM - PcAF

35

不,Dalvik不跨进程。

然而,Binder IPC机制可以让对象看起来像是迁移到其他进程和其Dalvik实例中。此外,内存管理非常擅长在所有需要它们的进程之间共享只读页面。托管典型应用程序的Dalvik进程是从zygote分叉出来的,并且已经映射了所有常见的Android库,因此不需要打开新的唯一副本。

来源: 使用多个进程的应用程序共享Dalvik实例吗?

还请查看以下链接:

http://davidehringer.com/software/android/The_Dalvik_Virtual_Machine.pdf

http://commonsware.com/blog/Articles/what-is-dalvik.html


6
Zygote 也被用于与所有应用程序共享系统可绘制资源,这样系统便只需加载一次按钮位图等内容。

1
这两面都有利弊:Zygote加载了一个下级版本的OpenSSL。一个期望加载它自己版本的OpenSSL的应用程序通常会被卡在下级版本上,因为Zygote在分叉之前已经加载了它。这包括支持FIPS的OpenSSL版本,其中应用程序试图使用经过验证的加密技术。 - jww

5
只是为了补充以上回答的一点,当Zygote接收到命令并进行分叉时,它使用写时复制技术。只有在新进程尝试修改内存时才会复制内存。
此外,Zygote在启动时加载的核心库是只读的,不能被修改。因此,它们不会被复制,而是与新分叉的进程共享。
所有这些都导致了快速启动和更少的内存占用。

4

Zygote并不是与Dalvik紧密相关的,它只是一个初始化过程。Zygote是Android用于启动应用程序的方法。它不必每次启动新进程时都从头开始加载整个系统和Android框架,而是在Zygote还没有执行任何特定于应用程序的操作之前,仅执行一次该过程,然后停止在那一点上。然后,当您想要启动应用程序时,Zygote进程会分叉,并且子进程在其离开的位置继续进行,将应用程序本身加载到VM中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接