<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                ### **概述** Android應用程序是運行在Dalvik虛擬機里面的,并且每一個應用程序對應有一個單獨的Dalvik虛擬機實例。Android應用程序中的Dalvik虛擬機實例實際上是從Zygote進程的地址空間拷貝而來的,這樣就可以加快Android應用程序的啟動速度。Dalvik虛擬機與Java虛擬機共享有差不多的特性,例如,它們都是解釋執行,并且支持即時編譯(JIT)、垃圾收集(GC)、Java本地方法調用(JNI)和Java遠程調試協議(JDWP)等,差別在于兩者執行的指令集是不一樣的,并且前者的指令集是基本寄存器的,而后者的指令集是基于堆棧的。 本系列文章主要將Dalvik虛擬機的內存管理、垃圾收集、即時編譯、Java本地調用、進程和線程管理等。理解Dalvik虛擬機的上述實現細節,有助于在運行時修改程序的行為,例如,攔截Java函數的調用。 * Dalvik虛擬機概述 * Dalvik虛擬機的啟動過程 * Dalvik虛擬機的運行過程 * JNI函數的注冊過程 * Dalvik虛擬機進程 * Dalvik虛擬機線程 #### **Dalvik虛擬機概述** Dalvik虛擬機由Dan Bornstein開發,名字來源于他的祖先曾經居住過的位于冰島的同名小漁村 Dalvik虛擬機起源于Apache Harmony項目,后者是由Apache軟件基金會主導的,目標是實現一個獨立的、兼容JDK 5的虛擬機,并根據Apache License v2發布 **Dalvik虛擬機與Java虛擬機的區別** ![](https://box.kancloud.cn/f2d177cf0d59d2b1ca430a4577431559_728x223.png) * 基于堆棧的Java指令(1個字節)和基于寄存器的Dalvik指令(2、4或者6個字節)各有優劣 * 一般而言,執行同樣的功能, Java虛擬機需要更多的指令(主要是load和store指令),而Dalvik虛擬機需要更多的指令空間 * 需要更多指令意味著要多占用CPU時間,而需要更多指令空間意味著指令緩沖(i-cache)更易失效 * Dalvik虛擬機使用dex(Dalvik Executable)格式的類文件,而Java虛擬機使用class格式的類文件 * 一個dex文件可以包含若干個類,而一個class文件只包括一個類 * 由于一個dex文件可以包含若干個類,因此它可以將各個類中重復的字符串只保存一次,從而節省了空間,適合在內存有限的移動設備使用 * 一般來說,包含有相同類的未壓縮dex文件稍小于一個已經壓縮的jar文件 **Dex文件的生成** ![](https://box.kancloud.cn/3fb3949d058324c82ec385245f2fa715_360x216.png) **Dex文件的優化** * 將invoke-virtual指令中的method index轉換為vtable index – 加快虛函數調用速度 * 將get/put指令中的field index轉換為byte offset – 加快實例成員變量訪問速度 * 將boolean/byte/char/short變種的get/put指令統一轉換為32位的get/put指令 – 減小VM解釋器的大小,從而更有效地利用CPU的i-cache * 將高頻調用的函數,例如String.length,轉換為inline函數 – 消除函數調用開銷 * 移除空函數,例如Object.`<init>` -- 消除空函數調用 * 將可以預先計算的數據進行預處理,例如預先生成VM根據class name查詢class的hash table – 節省Dex文件加載時間以及內存占用空間 * 將invoke-virtual指令中的method index轉換為vtable index ~~~ invoke-virtual {v1, v2}, method@BBBB → invoke-virtual-quick {v1,v2},vtable #0xhh ~~~ * 將get/put指令中的field index轉換為byte offset ~~~ iget-object v0, v2, field@BBBB → iget-object-quick v0,v2,[obj+0x100] ~~~ 備注: http://www.haogongju.net/art/1171347 http://mylifewithandroid.blogspot.com/2009/05/about-quick-method-invocation.html http://source.android.com/devices/tech/dalvik/dex-format.html **Dex文件的優化時機** * VM在運行時即時優化,例如使用DexClassLoader動態加載dex文件時。這時候需要指定一個當前進程有寫權限的用來保存odex的目錄。 * APP安裝時由具有root權限的installd優化。這時候優化產生的odex文件保存在特權目錄/data/dalvik-cache中。 * 編譯時優化。這時候編譯出來的jar/apk里面的classes.dex被提取并且優化為classes.odex保存在原jar/apk所在目錄,打包在system image中。 **內存管理** * Java Object Heap 大小受限,16M/24M/32M/48M/… * Bitmap Memory(External Memroy): 大小計入Java Object Heap * Native Heap 大小不受限 **Java Object Heap** * 用來分配Java對象。Dalvik虛擬機在啟動的時候,可以通過-Xms和-Xmx選項來指定Java Object Heap的最小值和最大值。 * Java Object Heap的最小和最大默認值為2M和16M。但是廠商會根據手機的配置情況進行調整,例如,G1、Droid、Nexus One和Xoom的Java Object Heap的最大值分別為16M、24M、32M 和48M。 * 通過ActivityManager.getMemoryClass可以獲得Dalvik虛擬機的Java Object Heap的最大值。 **Bitmap Memory** * 用來處理圖像。在HoneyComb之前,Bitmap Memory是在Native Heap中分配的,但是這部分內存同樣計入Java Object Heap中。這就是為什么我們在調用BitmapFactory相關的接口來處理大圖像時,會拋出一個OutOfMemoryError異常的原因:**java.lang.OutOfMemoryError:?bitmap?size?exceeds?VM?budget** * ?在HoneyComb以及更高的版本中,Bitmap Memory就直接是在Java Object Heap中分配了,這樣就可以直接接受GC的管理。 **Native Heap** * 在Native Code中使用malloc等分配出來的內存,這部分內存不受Java Object Heap的大小限制。 * 注意,不要因為Native Heap可以自由使用就濫用,因為濫用Native Heap會導致系統可用內存急劇減少,從而引發系統采取激進的措施來Kill掉某些進程,用來補充可用內存,這樣會影響系統體驗。 **垃圾收集(GC)** * Step 1: Mark,使用RootSet標記對象引用 * Step 2: Sweep,回收沒有被引用的對象 **GingerBread之前** * Stop-the-word,也就是垃圾收集線程在執行的時候,其它的線程都停止 * ?Full heap collection,也就是一次收集完全部的垃圾 * 一次垃圾收集造成的程序中止時間通常都大于100ms **GingerBread之后** * Cocurrent,也就是大多數情況下,垃圾收集線程與其它線程是并發執行的 * ?Partial collection,也就是一次可能只收集一部分垃圾 * 一次垃圾收集造成的程序中止時間通常都小于5ms * Dalvik虛擬機執行完成一次垃圾收集之后,我們通常可以看到類似以下的日志輸出: ~~~ D/dalvikvm(9050):?GC_CONCURRENT?freed?2049K,?65%?free?3571K/9991K,?external?4703K/5261K,?paused?2ms+2ms?? ~~~ * GC_CONCURRENT表示并行GC,2049K表示總共回收的內存,3571K/9991K表示Java Object Heap統計,即在9991K的Java Object Heap中,有3571K是正在使用的,4703K/5261K表示External Memory統計,即在5261K的External Memory中,有4703K是正在使用的,2ms+2ms表示垃圾收集造成的程序中止時間 **即時編譯(JIT)** * 從2.2開始支持JIT,并且是可選的,編譯時通過WITH_JIT宏進行控制 * 基于執行路徑(Executing Path)對熱門的代碼片斷進行優化(Trace JIT),傳統的Java虛擬機以Method為單位進行優化(Method JIT) * 可以利用運行時信息進行激進優化,獲得比靜態編譯語言更高的性能,如Lazy Unlocking機制,可以參考《Oracle JRockit: The Definitive Guide》一書 * 實現原理:http://blog.reverberate.org/2012/12/hello-jit-world-joy-of-simple-jits.html * 支持JDWP(Java Debug Wire Protocol)協議 * 每一個Dalvik虛擬機進程都都提供有一個端口來供調試器連接 * DDMS提供有一個轉發端口8870,通過它可以同時調試多個Dalvik虛擬機進程 ![](https://box.kancloud.cn/4fd364d735b86c4dd278211657ff7b6a_704x517.png) #### **Dalvik虛擬機的啟動過程** Dalvik虛擬機由Zygote進程啟動,然后再復制到System Server進程和應用程序進程 ![](https://box.kancloud.cn/baf670ce27a801cb8b9417e4ad226777_715x542.png) * startVM的過程中會創建一個JavaVMExt,并且該JavaVMExt關聯有一個JNIInvokeInterface,Native Code通過它來訪問Dalvik虛擬機 ![](https://box.kancloud.cn/531c80036cbe4e61f54d794ac0cd30d8_453x234.png) * startVM的過程中還會為當前線程關聯有一個JNIEnvExt,并且該JNIEnvExt 關聯有一個JNINativeInterface,Native Code通過它來調用Java函數或者訪問Java對象 ![](https://box.kancloud.cn/ff10442e32c364f9ef78d8e11c9686c3_536x573.png) **Dalvik虛擬機在Zygote進程啟動的過程中,還會進一步預加載Java和Android核心類庫以及系統資源** ![](https://box.kancloud.cn/da0751e0d400de8584e9528513560e71_591x446.png) **Dalvik虛擬機從Zygote進程復制到System Server進程之后,它們就通過COW(Copy On Write)機制共享同一個Dalvik虛擬機實例以及預加載類庫和資源** ![](https://box.kancloud.cn/49425482eb8c883d1aba8f3c07937b22_674x467.png) **Dalvik虛擬機從Zygote進程復制到應用程序進程之后,它們同樣會通過COW(Copy On Write)機制共享同一個Dalvik虛擬機實例以及預加載類庫和資源** ![](https://box.kancloud.cn/e5719c2c3313cbc0b2db6d0fb2cce8ca_678x463.png) #### **Dalvik虛擬機的運行過程** * Dalvik虛擬機在Zygote進程中啟動之后,就會以ZygoteInit.main為入口點開始運行 * Dalvik虛擬機從Zygote進程復制到System Server進程之后,就會以SystemServer.main為入口點開始運行 * Dalvik虛擬機Zygote進程復制到應用程序進程之后,就會以ActivityThread.main為入口點開始運行 * 上述入口點都是通過調用JNINativeInterface接口的成員函數CallStaticVoidMethod來進入的 J **JNINativeInterface->CallStaticVoidMethod對應的實現為CallStaticVoidMethodV** ![](https://box.kancloud.cn/d851ea3e8f137fe28184f4d3f08799ee_561x287.png) **CallStaticVoidMethodV調用dvmCallMethodV** ![](https://box.kancloud.cn/724b7293849b514df56f99980542bd3d_536x339.png) **在Dalvik虛擬機中,無論是Java函數,還是Native函數,都是通過Method結構體來描述的** ![](https://box.kancloud.cn/52380063cc25e7063abb85a917feca2d_702x392.png) > **備注**: > struct Method定義在文件dalvik/vm/oo/Object.h中 **在Dalivk虛擬機中,通過dvmIsNativeMethod判斷一個函數是Java函數還是Native函數** ![](https://box.kancloud.cn/476c92786b73391740068e107e55712e_506x55.png) > **備注**: > dvmIsNativeMethod定義在文件dalvik/vm/oo/Object.h中 **Native函數直接由CPU執行,Java函數由Dalvik虛擬機解釋執行,即通過dvmInterpret函數執行** ![](https://box.kancloud.cn/f6352c5dd6fba37975588cddfc5a8a12_638x546.png) **Dalvik虛擬機標準解釋器:dvmInterpretStd** ![](https://box.kancloud.cn/90bdda01aaba9f35ca6574e0c81f17ce_816x555.png) **Invoke-direct指令由函數invokeDirect執行** ![](https://box.kancloud.cn/438ce91f8254a796fcd8b58e6f320266_577x306.png) **函數invokeDirect調用?invokeMethod執行** ![](https://box.kancloud.cn/c216ef647340cd81277574243074f73a_703x496.png) #### **JNI函數的注冊過程** **JNI函數注冊示例 -- ClassWithJni** ![](https://box.kancloud.cn/e8fb506deddde63b6abfd75ccf04a17f_527x274.png) **JNI函數注冊示例 -- shy_luo_jni_ClassWithJni_nanosleep** ![](https://box.kancloud.cn/9216f0a09f730db97a201688550031dd_636x470.png) **System.loadLibrary** ![](https://box.kancloud.cn/ac707743e8a629c43ef330d9efb87331_596x235.png) **Runtime.loadLibrary** ![](https://box.kancloud.cn/a80eacf18648f5bd3889829c491fb9de_916x404.png) **Runtime.nativeLoad** ![](https://box.kancloud.cn/2628da643058b46a8d28107ea27cefcc_590x342.png) **dvmLoadNativeCode** ![](https://box.kancloud.cn/2415f740ea4592ec72f31985f214397a_562x606.png) **JNI_OnLoad** ![](https://box.kancloud.cn/9216f0a09f730db97a201688550031dd_636x470.png) **jniRegisterNativeMethods** ![](https://box.kancloud.cn/f53bf93adb88378c1132b0320054021c_558x377.png) **RegisterNatives** ![](https://box.kancloud.cn/c179b232c6513134a20fa3fceeaf9f2e_524x395.png) **dvmRegisterJNIMethod** ![](https://box.kancloud.cn/4fdac5ec86602308b2487a151dc2a1ad_649x335.png) **dvmUseJNIBridge** ![](https://box.kancloud.cn/582810a7f0d7432a096d54bd8e72941c_549x200.png) **dvmSetNativeFunc** ![](https://box.kancloud.cn/644e6cfd5427b4b5e062edfa3c72757e_502x306.png) #### **Dalvik虛擬機進程** * Dalvik虛擬機進程與下層的Linux進程是一一對應的 * 當ActivityManagerService啟動一個組件的時候,發現用來運行該組件的應用程序進程不存在,就會請求Zygote進程創建 * Zygote進程通過調用Zygote類的成員函數forkAndSpecialize來創建 **Zygote.forkAndSpecialize** ![](https://box.kancloud.cn/7065c5a5ef48996876031a108d019f6b_550x145.png) ![](https://box.kancloud.cn/5183998a4407e76eddfaa23e0427d168_532x215.png) **forkAndSpecializeCommon** ![](https://box.kancloud.cn/1cec59f4f3ac05686186ad9b3483c168_611x592.png) * Dalvik虛擬機線程與下層的Linux線程是一一對應的 * 在Java層中,可以創建一個Thread對象,并且調用該Thread對象的成員函數start來啟動一個Dalvik虛擬機線程 * 在Native層中,也可以通過創建一個Thread對象,并且調用該Thread對象的成員函數run來啟動一個Dalvik虛擬機線程 **在Java層創建Dalvik虛擬機線程--Thread.start** ![](https://box.kancloud.cn/59808cbaa43a84f03fcc8f0a5d9c8457_638x270.png) **VMThread.create** ![](https://box.kancloud.cn/99bcc1bf044de8fea806b9567a88d58e_582x450.png) **dvmCreateInterpThread** ![](https://box.kancloud.cn/ce7ead3b72882ddb9b1954c2b592f2d2_603x433.png) **線程啟動函數:interpThreadStart** ![](https://box.kancloud.cn/d150406c1fc754cb6aed57aedf43b802_448x225.png) **dvmCreateJNIEnv** ![](https://box.kancloud.cn/db77d4a3b68dc83fc13c64f4b438307d_1024x414.png) **在Native層創建Dalvik虛擬機線程--Thread::run** ![](https://box.kancloud.cn/d8fd4591e2b9172c7de4cd40b7b0a542_568x322.png) **createThreadEtc** ![](https://box.kancloud.cn/7a8cfed02e08746c44a0253658cf9c7f_561x181.png) **androidCreateThreadEtc** ![](https://box.kancloud.cn/7c2ebecc1244f5c7b29f5b6a44fbe40c_541x216.png) > **注意**,函數指針gCreateThreadFn所指向的函數在Dalvik虛擬機啟動時已經被修改為javaCreateThreadEtc **javaCreateThreadEtc** ![](https://box.kancloud.cn/2a47b5b212854dbdb3483077d2c1dc9d_602x377.png) **androidCreateRawThreadEtc** ![](https://box.kancloud.cn/6d8ac5e9b27007b29810cb5e297a38cb_558x318.png) **AndroidRuntime::javaThreadShell** ![](https://box.kancloud.cn/84dc7372916e7590db4f7f3a9337b4be_527x377.png) **javaAttachThread** ![](https://box.kancloud.cn/da97b2d4f64c53a8b151fdf8c5375f4b_490x344.png) **AttachCurrentThread** ![](https://box.kancloud.cn/3f623c5e3f980d04ea1bde2d9e27e1cd_536x143.png) **attachThread** ![](https://box.kancloud.cn/839acd089295b8089663275dca612310_567x344.png) **dvmAttachCurrentThread** ![](https://box.kancloud.cn/232421b654ffa20d868da135ee68e218_588x340.png)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看