Android 源碼分析(十) Dalvik 虛擬機創建過程
一. 介紹Dalvik
1.java的運行需要JVM(後面有大量篇幅介紹),同樣android中使用了java語言,也需要一個VM。針對手機處理器和內存等硬件資源不足而推出來的一款VM,為android運行提供環境,叫DVM。
2.Dalvik虛擬機允許多個instance的存在。實際上android中的每一個app都是運行在自己VM實例之中(沙盒)。每一個VM實例在linux中又是一個單獨的進程,所以可以認為是同一個概念。運行在自己的DVM進程之中,不同的app不會相互幹擾,且不會因為一個DVM的崩潰導致所有的app進程都崩潰。這點來說,Android dvm的進程和Linux的進程, 應用程序的進程 概念類似。
3.與JVM的區別:
1.基於架構的不同。JVM是基於棧的架構,而DVM是基於寄存器架構。
2.jvm運行的是字節碼文件,而dvm運行自己定義的dex文件格式。
JVM編譯過程 java->class->jar
DVM編譯過程java->class->dex
總結dvm與jvm區別:
區別一:dvm執行的是.dex格式文件 jvm執行的是.class文件 android程序編譯完之後生產.class文件,然後,dex工具會把.class文件處理成.dex文件,然後把資源文件和.dex文件等打包成.apk文件。apk就是android package的意思。 jvm執行的是.class文件。
區別二:dvm是基於寄存器的虛擬機 而jvm執行是基於虛擬棧的虛擬機。寄存器存取速度比棧快的多,dvm可以根據硬件實現最大的優化,比較適合移動設備。
區別三:.class文件存在很多的冗余信息,dex工具會去除冗余信息,並把所有的.class文件整合到.dex文件中。減少了I/O操作,提高了類的查找速度
一張圖了解dvm主要做的事:
參考: https://blog.csdn.net/u010355144/article/details/47682797
二.Dalvik啟動過程
//AndroidRuntime.cpp int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, boolzygote) { JavaVMInitArgs initArgs; char propBuf[PROPERTY_VALUE_MAX]; char stackTraceFileBuf[sizeof("-Xstacktracefile:")-1 + PROPERTY_VALUE_MAX]; char jniOptsBuf[sizeof("-Xjniopts:")-1 + PROPERTY_VALUE_MAX]; char heapstartsizeOptsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX]; char heapsizeOptsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX]; char heapgrowthlimitOptsBuf[sizeof("-XX:HeapGrowthLimit=")-1 + PROPERTY_VALUE_MAX]; char heapminfreeOptsBuf[sizeof("-XX:HeapMinFree=")-1 + PROPERTY_VALUE_MAX]; char heapmaxfreeOptsBuf[sizeof("-XX:HeapMaxFree=")-1 + PROPERTY_VALUE_MAX]; char usejitOptsBuf[sizeof("-Xusejit:")-1 + PROPERTY_VALUE_MAX]; char jitmaxsizeOptsBuf[sizeof("-Xjitmaxsize:")-1 + PROPERTY_VALUE_MAX]; char jitinitialsizeOptsBuf[sizeof("-Xjitinitialsize:")-1 + PROPERTY_VALUE_MAX]; char jitthresholdOptsBuf[sizeof("-Xjitthreshold:")-1 + PROPERTY_VALUE_MAX]; char useJitProfilesOptsBuf[sizeof("-Xjitsaveprofilinginfo:")-1 + PROPERTY_VALUE_MAX]; char jitprithreadweightOptBuf[sizeof("-Xjitprithreadweight:")-1 + PROPERTY_VALUE_MAX]; char jittransitionweightOptBuf[sizeof("-Xjittransitionweight:")-1 + PROPERTY_VALUE_MAX]; char gctypeOptsBuf[sizeof("-Xgc:")-1 + PROPERTY_VALUE_MAX]; char backgroundgcOptsBuf[sizeof("-XX:BackgroundGC=")-1 + PROPERTY_VALUE_MAX]; char heaptargetutilizationOptsBuf[sizeof("-XX:HeapTargetUtilization=")-1 + PROPERTY_VALUE_MAX]; char cachePruneBuf[sizeof("-Xzygote-max-boot-retry=")-1 + PROPERTY_VALUE_MAX]; char dex2oatXmsImageFlagsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX]; char dex2oatXmxImageFlagsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX]; char dex2oatXmsFlagsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX]; char dex2oatXmxFlagsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX]; char dex2oatCompilerFilterBuf[sizeof("--compiler-filter=")-1 + PROPERTY_VALUE_MAX]; char dex2oatImageCompilerFilterBuf[sizeof("--compiler-filter=")-1 + PROPERTY_VALUE_MAX]; char dex2oatThreadsBuf[sizeof("-j")-1 + PROPERTY_VALUE_MAX]; char dex2oatThreadsImageBuf[sizeof("-j")-1 + PROPERTY_VALUE_MAX]; char dex2oat_isa_variant_key[PROPERTY_KEY_MAX]; char dex2oat_isa_variant[sizeof("--instruction-set-variant=") -1 + PROPERTY_VALUE_MAX]; char dex2oat_isa_features_key[PROPERTY_KEY_MAX]; char dex2oat_isa_features[sizeof("--instruction-set-features=") -1 + PROPERTY_VALUE_MAX]; char dex2oatFlagsBuf[PROPERTY_VALUE_MAX]; char dex2oatImageFlagsBuf[PROPERTY_VALUE_MAX]; char extraOptsBuf[PROPERTY_VALUE_MAX]; char voldDecryptBuf[PROPERTY_VALUE_MAX]; ... /* * Initialize the VM. * * The JavaVM* is essentially per-process, and the JNIEnv* is per-thread. * If this call succeeds, the VM is ready, and we can start issuing * JNI calls. */ if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) { ALOGE("JNI_CreateJavaVM failed\n"); return -1; } return 0; } void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote) { /* start the virtual machine */ JniInvocation jni_invocation; jni_invocation.Init(NULL); JNIEnv* env; if (startVm(&mJavaVM, &env, zygote) != 0) { return; } onVmCreated(env); /* * Register android functions. */ if (startReg(env) < 0) { ALOGE("Unable to register all android natives\n"); return; } }
//Dalvik虛擬機在Zygote進程中的啟動過程,這個啟動過程主要就是完成了以下四個事情:
//1. 創建了一個Dalvik虛擬機實例;
//2. 加載了Java核心類及其JNI方法;
//3. 為主線程的設置了一個JNI環境;
//4. 註冊了Android核心類的JNI方法。
Zygote 啟動Dalvik作用:
1. Zygote進程為Android系統準備好了一個Dalvik虛擬機實例,以後Zygote進程在創建Android應用程序進程的時候,就可以將它自身的Dalvik虛擬機實例復制到新創建Android應用程序進程中去,從而加快了Android應用程序進程的啟動過程。
2.Java核心類和Android核心類(位於dex文件中),以及它們的JNI方法(位於so文件中),都是以內存映射的方式來讀取的,因此,Zygote進程在創建Android應用程序進程的時候,除了可以將自身的Dalvik虛擬機實例復制到新創建的Android應用程序進程之外,還可以與新創建的Android應用程序進程共享Java核心類和Android核心類,以及它們的JNI方法,這樣就可以節省內存消耗。
3.Zygote進程為了加快Android應用程序進程的啟動過程,犧牲了自己的啟動速度,因為它需要加載大量的Java核心類,以及註冊大量的Android核心類JNI方法。Dalvik虛擬機在加載Java核心類的時候,還需要對它們進行驗證以及優化,這些通常都是比較耗時的。又由於Zygote進程是由init進程啟動的,也就是說Zygote進程在是開機的時候進行啟動的,因此,Zygote進程的犧牲是比較大的。不過畢竟我們在玩手機的時候,很少會關機,也就是很少開機,因此,犧牲Zygote進程的啟動速度是值得的,換來的是Android應用程序的快速啟動。
Android 源碼分析(十) Dalvik 虛擬機創建過程