<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>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                [原文出處------------Android運行時ART簡要介紹和學習計劃](http://blog.csdn.net/luoshengyang/article/details/39256813) Android在4.4就已推出新運行時ART,準備替代用了有些時日的Dalvik。不過當時尚屬測試版,主角仍是Dalvik。 直到今年的Google I/O大會,ART才正式取代Dalvik。這個消息在科技界引起不小轟動,也吸引不少技術人員對它的“技術分析”。可惜這些“技術分析”不過是引用了官方的數據和圖表而已。這一系列文章將對ART進行真正的技術分析。老規矩,分析前先進行簡要介紹和制定學習計劃。 ART的發布之所以引起大家的關注,是因為Andoid與iOS相比,一直被人詬病它的流暢性。Android的流暢性問題,有一部分原因就歸結于它的應用程序和部分系統服務是運行虛擬機之上的,也就是運行在Dalvik虛擬機之上,而iOS的應用程序和系統服務都是直接執行本地機器指令的。除了使用ART替換Dalvik之外,我們也應當看到,Android從3.0開始,就不遺余力地改進系統的流暢性。例如,3.0增加了對應用程序2D UI的硬件加速渲染,也就是GPU渲染。在此之前,應用程序的2D UI一直都是使用軟件渲染,也就是CPU渲染。又如4.1通過Project Butter,在UI架構中引入了VSYNC、Triple Buffer和HWComposer等技術,極大地提高UI的流暢性。 ART之所以會比Dalvik快,是因為ART執行的是本地機器指令,而Dalvik執行的是Dex字節碼,通過通過解釋器執行。盡管Dalvik也會對頻繁執行的代碼進行JIT生成本地機器指令來執行,但畢竟在應用程序運行的過程中將Dex字節碼翻譯成本地機器機器指令也會影響到應用程序本身的執行,因此即使Dalvik使用了JIT,也在一定程度上也比不上直接就可以執行本地機器指令的運行時。 在前面[Android ART運行時無縫替換Dalvik虛擬機的過程分析](http://blog.csdn.net/luoshengyang/article/details/18006645)一文中,我們提到,ART像Dalvik一樣,都實現Java虛擬機接口,如圖1所示: ![](https://box.kancloud.cn/60c3b75d729bf49e79f86735e09bc1a7_653x445.jpeg) 圖1 Dalvik、ART和Java VM的關系 Zygote進程在啟動的過程中,正是通過圖1所示的接口創建Dalvik或者ART虛擬機的,這樣看來,ART雖然執行的本地機器指令,但是它表面看來,又是一個不折不扣的虛擬機。也正是因為這樣,ART才可以在不重新編譯APK的基礎上,直接可以加載和運行APK。這也是ART運行時可以無縫替換Dalvik運行時的原理。因此,我們就可以得出一個結論:ART是一個執行本地機器指令的虛擬機。這個結論似乎有點矛盾,既然是執行本地機器指令,為什么又稱為虛擬機呢?從接下來的文章分析可以知道,ART除了實現Java虛擬機接口之外,其內部還有垃圾收集機制,同時還有Java核心類庫調用,因此,隨著對ART的深入分析,我們就認為這個結論是不矛盾的了。 上面提到,ART才可以在不重新編譯APK的基礎上,直接對其進行加載和運行,這是由于APK在安裝時被執行了AOT。AOT(Ahead Of Time)是相對JIT(Just In Time)而言的。也就是在APK運行之前,就對其包含的Dex字節碼進行翻譯,得到對應的本地機器指令,于是就可以在運行時直接執行了。這種技術不但使得我們可以不對原有的APK作任何修改,還可以使得這些APK只需要在安裝時翻譯一次,就可以無數次以本地機器指令的形式運行。這種技術與我們用C/C++語言編寫一個程序,然后用GCC編譯得到一個可執行程序,最后這個可執行程序就可以無數次地加載到系統執行,是差不多的。 在ART中,打包在APK里面的Dex字節碼是通過LLVM翻譯成本地機器指令的。LLVM是一個用來快速開發自己的編譯器的框架系統,關于它的介紹,可以參考它的作者之一[Chris Lattner](http://www.nondot.org/sabre/)寫的這篇文章:[LLVM](http://www.aosabook.org/en/llvm.html) 。說起Chris Lattner,他就是Apple今年發布的Swift語言的首席架構師啊,所以我們就可以感受到LLVM有多強大了。總體來說,基于LLVM架構開發的編譯器的執行過程如圖2所示: ![](https://box.kancloud.cn/1bf2502032ee88543f7ca3cfd4f0c277_489x75.png) 圖2 基于LLVM架構開發的編譯器執行過程 其中,前端(Frontend)對輸入的源代碼(Source Code)進行語法分析后,生成一棵抽象語法樹(Abstract Syntax Tree,AST),并且可以進一步將得到的抽象語法樹轉化一種稱為LLVM IR的中間語言。LLVM IR是一種與編程語言無關的中間語言,也就是說,不管是C語言,還是Fortran、Ada語言編寫的源文件,經過語法分析后,最終都可以得到一個對應的LLVM IR文件。這個LLVM IR文件可以作為后面的優化器(Optimizer)和后端(Backend)的輸入文件。優化器對LLVM IR文件進行優化,例如消除代碼里面的冗余計算,以提到最終生成的代碼的執行效率。后端負責生成最終的機器指令。 LLVM的上述架構大大簡化開發編譯器的流程,因為開發者需要關注的僅僅是前端,然后就可以利用現成的優化器來進行代碼優化,并且利用現成的后端生成各種體系結構相關的機器指令,如圖3所示: ![](https://box.kancloud.cn/01096f9be4a79f04bce3ac711e1e71f1_575x209.png) 圖3 利用現成的與語言無關的優化器和后端為語言相關的前端生成各種體系結構相關的機器指令 在圖3中,我們分別為C、Fortran和Ada三種語言開發三個不同的前端,然后利用現成的優化器對它們生成的LLVM IR語言進行優化,并且通過現成的后端生成X86、PowerPC和ARM三種不同體系結構的機器指令。 如果我們沒有忘記,在Dalvik運行時中,APK在安裝的時候,安裝服務PackageManagerService會通過守護進程installd調用一個工具dexopt對打包在APK里面包含有Dex字節碼的classes.dex進行優化,優化得到的文件保存在/data/dalvik-cache目錄中,并且以.odex為后綴名,表示這是一個優化過的Dex文件。在ART運行時中,APK在安裝的時候,同樣安裝服務PackageManagerService會通過守護進程installd調用另外一個工具dex2oat對打包在APK里面包含有Dex字節碼進翻譯。這個翻譯器實際上就是基于LLVM架構實現的一個編譯器,它的前端是一個Dex語法分析器。翻譯后得到的是一個ELF格式的oat文件,這個oat文件同樣是以.odex后綴結束,并且也是保存在/data/dalvik-cache目錄中。 ELF是Linux系統使用的一種文件格式,我們平時接觸的靜態庫、動態庫和可執行文件都是以這種格式保存的,但是由dex2oat工具生成的oat文件與上述三種文件都不一樣,它有兩個特殊的段oatdata和oatexec,分別用來儲存原來打包在APK里面的dex文件和翻譯這個dex文件里面的類方法得到本地機器指令,如圖4所示: ![](https://box.kancloud.cn/4dc36abf8f1d3343a178becb4c1fe6fb_638x693.jpeg) 圖4 ART翻譯classes.dex后得到的ELF格式的oat文件 在oat文件的動態段(dymanic section)中,還導出了三個符號oatdata、oatexec和oatlastword,分別用來描述oatdata和oatexec段加段到內存后的起止地址。在oatdata段中,包含了兩個重要的信息,一個信息是原來的classes.dex文件的完整內容,另一個信息引導ART找到classes.dex文件里面的類方法所對應的本地機器指令,這些本地機器指令就保存在oatexec段中。 舉個例子說,我們在classes.dex文件中有一個類A,那么當我們知道類A的名字后,就可以通過保存在oatdata段的dex文件得到類A的所有信息,比如它的父類、成員變量和成員函數等。另一方面,類A在oatdata段中有一個對應的OatClass結構體。這個OatClass結構體描述了類A的每一個方法所對應的本地機器指令在oatexec段的位置。也就是說,當我們知道一個類及其某一個方法的名字(簽名)之后,就可以通過oatdata段的dex文件內容和OatClass結構體找到其在oatexec段的本地機器指令,這樣就可以執行這個類方法了。 通過上面的分析,我們就將ART的運行原理都簡要地介紹了,總結如下: 1. 在Android系統啟動過程中創建的Zygote進程利用ART運行時導出的Java虛擬機接口創建ART虛擬機。 2. APK在安裝的時候,打包在里面的classes.dex文件會被工具dex2oat翻譯成本地機器指令,最終得到一個ELF格式的oat文件。 3. APK運行時,上述生成的oat文件會被加載到內存中,并且ART虛擬機可以通過里面的oatdata和oatexec段找到任意一個類的方法對應的本地機器指令來執行。 對于第1點,ART虛擬機的創建過程中,可以參考前面[Android ART運行時無縫替換Dalvik虛擬機的過程分析](http://blog.csdn.net/luoshengyang/article/details/18006645)一文。 對于第2點,APK里面的Dex字節碼被dex2oat工具翻譯生本地機器指令的過程,掌握它需要有扎實的編譯知識。由于知識、能力、時間有限,因此這一部分的內容我們就略過不分析了,但是這將不會影響我們對ART運行時的理解。 對于第3點,是我們理解ART運行時的關鍵所在。以ART虛擬機的啟動過程為例,從前面A[ndroid ART運行時無縫替換Dalvik虛擬機的過程分析](http://blog.csdn.net/luoshengyang/article/details/18006645)一文可以知道,在AndroidRuntime類的成員函數start中,ART虛擬機創建和初始化完成后,Zygote進程就會通過它導出的JNI接口CallStaticVoidMethod使得它以指定的類方法為入口正式進入運行狀態,如下所示: ``` void AndroidRuntime::start(const char* className, const char* options) { ...... /* start the virtual machine */ JniInvocation jni_invocation; jni_invocation.Init(NULL); JNIEnv* env; if (startVm(&mJavaVM, &env) != 0) { return; } ...... /* * Start VM. This thread becomes the main thread of the VM, and will * not return until the VM exits. */ char* slashClassName = toSlashClassName(className); jclass startClass = env->FindClass(slashClassName); if (startClass == NULL) { ALOGE("JavaVM unable to locate class '%s'\n", slashClassName); /* keep going */ } else { jmethodID startMeth = env->GetStaticMethodID(startClass, "main", "([Ljava/lang/String;)V"); if (startMeth == NULL) { ALOGE("JavaVM unable to find main() in '%s'\n", className); /* keep going */ } else { env->CallStaticVoidMethod(startClass, startMeth, strArray); #if 0 if (env->ExceptionCheck()) threadExitUncaughtException(env); #endif } } ...... } ``` 這個函數定義在文件frameworks/base/core/jni/AndroidRuntime.cpp中。 在AndroidRuntime類的成員函數start中,參數className的值等于“com.android.internal.os.ZygoteInit”,本地變量env是從調用另外一個成員函數startVm創建的ART虛擬機獲得的JNI接口。函數的目標就是要找到一個名稱為com.android.internal.os.ZygoteInit的類,以及它的靜態成員函數main,然后就以這個函數為入口,開始運行ART虛擬機。為此,函數執行了以下步驟: 1. 調用JNI接口FindClass加載com.android.internal.os.ZygoteInit類。 2. 調用JNI接口GetStaticMethodID找到com.android.internal.os.ZygoteInit類的靜態成員函數main。 3. 調用JNI接口CallStaticVoidMethod開始執行com.android.internal.os.ZygoteInit類的靜態成員函數main。 注意,在第3步中,要執行的是CallStaticVoidMethod開始執行com.android.internal.os.ZygoteInit類的靜態成員函數main的本地機器指令,而不是Dex字節碼。這樣就引出以下三個關鍵問題: 1. ART如何找到com.android.internal.os.ZygoteInit類? 2. ART如何找到com.android.internal.os.ZygoteInit類的靜態成員函數main? 3. ART如何找到com.android.internal.os.ZygoteInit類的靜態成員函數main的本地機器指令? 解決上述三個問題所需要的信息都存在于dex2oat工具生成的oat文件中。因此,在接下來的文章中,我們將通過分析dex2oat工具生成的oat文件來回答上述三個問題,使得我們可以更加好地理解ART的工作原理。 如上所述,由于ART在查找類方法時,需要用到保存在oat文件的oatdata段的原dex文件內容,實質上就是要對dex文件進行解析,以獲得相關的信息。這與Dalvik虛擬機在dex文件中查找類和方法信息的過程是一樣的。這意味著要理解ART運行時,必須先要理解Dalvik虛擬機。Dalvik虛擬機的相關知識可以參考[Dalvik虛擬機簡要介紹和學習計劃](http://blog.csdn.net/luoshengyang/article/details/8852432)這個系列的文章。這告訴我們一個道理,舊的知識并沒有過時,它對我們學習新的知識是有幫助的,有時候甚至是必須的。所以大家就不要覺得最前面寫的那些基于Android 2.3版本的文章是沒有用的了。我們在學習一樣新東西的時候,無論是新的知識,還是舊的知識,對我們理解它的原理,都是很有幫助的! 我們除了要以dex2oat工具生成的oat文件作為切入點來分析ART運行時之外,還會結合ART運行時的垃圾收集機制來說明ART運行時與Dalvik虛擬機一樣也是一個虛擬機,以此加深對ART運行時的理解。與Dalvik虛擬機的垃圾收集機制相比,ART運行時的垃圾收集機制更為復雜,由此帶來的垃圾收集效率也更高。因此我們在分析ART運行時的垃圾收集機制之前,先會分析Dalvik虛擬機的垃圾收集機制。一方面是有利于我們循序漸進、由簡而繁地講解ART運行時的垃圾收集原理,另一方面也方便我們對比ART運行時和Dalvik虛擬機的垃圾收集機制有哪些不同,從而可以更好地理解為ART運行時的垃圾收集效率更高。 綜上所述,接下來我們就按照以下幾個情景來分析ART的工作原理: 1. [ART加載oat文件的過程](http://blog.csdn.net/luoshengyang/article/details/39307813)。 2. [ART查找類和方法的過程](http://blog.csdn.net/luoshengyang/article/details/39533503)。 3. [ART查找類方法的本地機器指令的過程](http://blog.csdn.net/luoshengyang/article/details/40289405)。 4. [Dalvik虛擬機的垃圾收集過程](http://blog.csdn.net/luoshengyang/article/details/41338251)。 5. [ART的垃圾收集過程](http://blog.csdn.net/luoshengyang/article/details/42072975)。 以上情景將基于Android 4.4源碼進行分析,一方面是因為Android L版本的源碼還沒有放出來,另一方面是相信萬變不離其宗,即使Androd L版本的ART實現有變化,但是基本的原理還是一樣的。
                  <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>

                              哎呀哎呀视频在线观看