Dalvik虛擬機(jī)學(xué)習(xí)之路

1.Dalvik虛擬機(jī)和Java虛擬機(jī)的區(qū)別

Dalvik虛擬機(jī)使用的是dex(Dalvik Executable)格式的類文件,而Java虛擬機(jī)使用的是class格式的類文件冕房。一個(gè)dex文件可以包含若干個(gè)類肛宋,而一個(gè)class文件只包括一個(gè)類瘟则。由于一個(gè)dex文件可以包含若干個(gè)類,因此它就可以將各個(gè)類中重復(fù)的字符串和其它常數(shù)只保存一次,從而節(jié)省了空間药版,這樣就適合在內(nèi)存和處理器速度有限的手機(jī)系統(tǒng)中使用。

Dalvik虛擬機(jī)使用的指令是基于寄存器的白魂,而Java虛擬機(jī)使用的指令集是基于堆棧的汽纤。

寄存器(Register),是中央處理器內(nèi)的其中組成部分福荸。寄存器是有限存貯容量的高速存貯部件蕴坪,它們可用來暫存指令、數(shù)據(jù)地址敬锐。在中央處理器的控制部件中背传,包含的寄存器有指令寄存器(IR)和程序計(jì)數(shù)器。在中央處理器的算術(shù)及邏輯部件中台夺,包含的寄存器有累加器径玖。

每一個(gè)Android應(yīng)用在底層都會(huì)對應(yīng)一個(gè)獨(dú)立的Dalvik虛擬機(jī)實(shí)例,其代碼在虛擬機(jī)的解釋器下得以執(zhí)行颤介。

有一個(gè)特殊的虛擬機(jī)進(jìn)程Zygote梳星,他是虛擬機(jī)實(shí)例的孵化器。它在系統(tǒng)啟動(dòng)的時(shí)候就會(huì)產(chǎn)生滚朵,它會(huì)完成虛擬機(jī)的初始化冤灾、庫的加載、預(yù)制類庫和初始化的操作辕近。如果系統(tǒng)需要一個(gè)新的虛擬機(jī)實(shí)例韵吨,它會(huì)迅速復(fù)制自身,以最快的速度提供給系統(tǒng)移宅。對于一些只讀的系統(tǒng)庫归粉,所有虛擬機(jī)實(shí)例都和Zygote共享一塊內(nèi)存區(qū)域。

2.Dalvik的工作流程

Dalvik虛擬機(jī)支持已轉(zhuǎn)換為.dex(即Dalvik Executable)格式的Java應(yīng)用程序的運(yùn)行吞杭,.dex格式是專為Dalvik設(shè)計(jì)的一種壓縮格式盏浇,適合內(nèi)存和處理器速度有限的系統(tǒng)。(dx 是一套工具芽狗,可以將 Java .class 轉(zhuǎn)換成 .dex 格式. 一個(gè)dex檔通常會(huì)有多個(gè).class绢掰。由于dex有時(shí)必須進(jìn)行最佳化,會(huì)使檔案大小增加1-4倍童擎,以O(shè)DEX結(jié)尾滴劲。)


Dalvik工作模型

2.1 java-class

首先讀取源碼,一個(gè)一個(gè)字節(jié)的讀取進(jìn)來顾复,找出來我們Java定義的關(guān)鍵字班挖,比如if ,else,for,while,finally,等這個(gè)步驟就是叫做詞法分析過程

第二步:檢查第一步讀取出來的關(guān)鍵字是否符合Java語言規(guī)范,比如if后面跟的是不是一個(gè)Boolean類型的表達(dá)式芯砸,這個(gè)過程就叫做語法分析

第三步:經(jīng)過以上2個(gè)步驟詞法分析萧芙,語法分析给梅,基本上已經(jīng)按照J(rèn)ava規(guī)范了,接下來就是這些拼裝的代碼要表達(dá)什么意思双揪,也就是語義分析


class字節(jié)碼模型

注:Java源碼中的類名动羽,方法名,變量名渔期,居然都是以字符串形式存儲(chǔ)在常量池中运吓。所以,圖class字節(jié)碼模型中的this_class和super_class分別指向兩個(gè)字符串疯趟,代表本類的名字和基類的名字拘哨。

常量池?cái)?shù)組的元素類型

常量池結(jié)構(gòu)

常量池常見類型:

CONSTANT_Utf8_info:就是字符串

CONSTANT_Class_info:類信息

CONSTANT_NameAndType_Info:用來描述方法/成員名以及類型信息的

Methodref_Info信峻,InterfaceMethodref_Info,F(xiàn)ieldref_Info

用于描述方法姨夹、接口信息和成員變量。

Methodref_Info矾策,InterfaceMethodref_Info,F(xiàn)ieldref_Info數(shù)據(jù)結(jié)構(gòu)

常量池就不說這么多了逃糟,有興趣的就自行解析。解析方法為:javap -verbose xxxx.class

2.2 class-dex

前言:Android平臺(tái)中沒有直接使用Class文件格式蓬豁,是因?yàn)樵缙诘腁nrdroid手機(jī)內(nèi)存绰咽,存儲(chǔ)都比較小,而Class文件顯然有很多可以優(yōu)化的地方不皆,比如每個(gè)Class文件都有一個(gè)常量池,里邊存儲(chǔ)了一些字符串旺聚。一串內(nèi)容完全相同的字符串很有可能在不同的Class文件的常量池中存在眶蕉,這就是一個(gè)可以優(yōu)化的地方造挽。

傳統(tǒng)Class文件是一個(gè)Java源碼文件會(huì)生成一個(gè).Class文件弄痹,而Android是把所有Class文件進(jìn)行合并界酒,優(yōu)化嘴秸,然后生成一個(gè)最終的class.dex岳掐,如此饭耳,多個(gè)Class文件里如果有重復(fù)的字符串,當(dāng)把它們都放到一個(gè)dex文件的時(shí)候纲酗,只要一份就可以了嘛觅赊。


dex文件模型

2.3 dex-odex

odex文件就是dex文件具體在某個(gè)系統(tǒng)(不同手機(jī)吮螺,不同手機(jī)的OS帕翻,不同版本的OS等)上的優(yōu)化嘀掸。odex文件的優(yōu)化依賴系統(tǒng)上的幾個(gè)核心模塊(由BOOTCLASSPATH環(huán)境變量給出,一般是/system/framework/下的jar包泉蝌,尤其是core.jar)梨与,主要還是為了提高Dalvik虛擬機(jī)的運(yùn)行速度文狱,這部分內(nèi)容了解即可瞄崇。

odex文件模型

3.內(nèi)存管理

3.1物理內(nèi)存

物理內(nèi)存即移動(dòng)設(shè)備上的RAM,當(dāng)啟動(dòng)一個(gè)Android程序時(shí)腮郊,會(huì)啟動(dòng)一個(gè)Dalvik VM進(jìn)程筹燕,系統(tǒng)會(huì)給它分配固定的內(nèi)存空間(16M,32M不定)撒踪,這塊內(nèi)存空間會(huì)映射到RAM上某個(gè)區(qū)域制妄。然后這個(gè)Android程序就會(huì)運(yùn)行在這塊空間上。Java里會(huì)將這塊空間分成Stack棧內(nèi)存和Heap堆內(nèi)存衔掸。stack里存放對象的引用敞映,heap里存放實(shí)際對象數(shù)據(jù)凌埂。

注:android使用了pagingmemory-mapping(mmapping)的機(jī)制來管理內(nèi)存瞳抓。這意味著任何你修改的內(nèi)存(無論是通過分配新的對象還是去訪問mmaped pages中的內(nèi)容)都會(huì)貯存在RAM中孩哑,而且不能被paged out。因此唯一完整釋放內(nèi)存的方法是釋放那些你可能hold住的對象的引用胳蛮,當(dāng)這個(gè)對象沒有被任何其他對象所引用的時(shí)候丛晌,它就能夠被GC回收了澎蛛。只有一種例外是:如果系統(tǒng)想要在其他地方重用這個(gè)對象。

3.1.1Java Object Heap

Java Object Heap是用來分配Java對象的桐经,也就是我們在代碼new出來的對象都是位于Java Object Heap上的浙滤。Dalvik虛擬機(jī)在啟動(dòng)的時(shí)候纺腊,可以通過-Xms和-Xmx選項(xiàng)來指定Java Object Heap的最小值和最大值摹菠。可以通過ActivityManager類的成員函數(shù)getMemoryClass來獲得Dalvik虛擬機(jī)的Java Object Heap的最大值。Android應(yīng)用程序進(jìn)程能夠使用的最大內(nèi)存指的是能夠用來分配Java Object的堆煮寡。

3.1.2Bitmap Memory?

它是用來處理圖像的幸撕。在3.0以及更高的版本中外臂,Bitmap Memory就直接是在Java Object Heap中分配了宋光,這樣就可以直接接受GC的管理。

3.1.3Native Heap

Native Heap就是在Native Code中使用malloc等分配出來的內(nèi)存逛漫,這部分內(nèi)存是不受Java Object Heap的大小限制的酌毡,也就是它可以自由使用枷踏,當(dāng)然它是會(huì)受到系統(tǒng)的限制掰曾。但是有一點(diǎn)需要注意的是,不要因?yàn)镹ative Heap可以自由使用就濫用客蹋,因?yàn)闉E用Native Heap會(huì)導(dǎo)致系統(tǒng)可用內(nèi)存急劇減少孽江,從而引發(fā)系統(tǒng)采取激進(jìn)的措施來Kill掉某些進(jìn)程岗屏,用來補(bǔ)充可用內(nèi)存这刷,這樣會(huì)影響系統(tǒng)體驗(yàn)。

4.垃圾收集

Dalvik虛擬機(jī)可以自動(dòng)回收那些不再使用了的Java Object似袁,也就是那些不再被引用了的Java Object昙衅。垃圾自動(dòng)收集機(jī)制將開發(fā)者從內(nèi)存問題中解放出來而涉,極大地提高了開發(fā)效率联予,以及提高了程序的可維護(hù)性沸久。

Dalvik虛擬機(jī)使用Mark-Sweep算法來進(jìn)行垃圾收集麦向。顧名思義,Mark-Sweep算法就是為Mark和Sweep兩個(gè)階段進(jìn)行垃圾回收话告。其中沙郭,Mark階段從根集(Root Set)開始病线,遞歸地標(biāo)記出當(dāng)前所有被引用的對象,而Sweep階段負(fù)責(zé)回收那些沒有被引用的對象绑莺。

當(dāng)Dalvik虛擬機(jī)成功地在堆上分配一個(gè)對象之后纺裁,會(huì)檢查一下當(dāng)前分配的內(nèi)存是否超出一個(gè)閥值欺缘。

GC_FOR_MALLOC:表示是在堆上分配對象時(shí)內(nèi)存不足觸發(fā)的GC谚殊。

GC_CONCURRENT:表示是在已分配內(nèi)存達(dá)到一定量之后觸發(fā)的GC蛤铜。

GC_EXPLICIT:表示是應(yīng)用程序調(diào)用System.gc围肥、VMRuntime.gc接口或者收到SIGUSR1信號時(shí)觸發(fā)的GC虐先。

GC_BEFORE_OOM:表示是在準(zhǔn)備拋OOM異常之前進(jìn)行的最后努力而觸發(fā)的GC派敷。

GC工作模型

Dalvik虛擬機(jī)支持非并行和并行兩種GC篮愉。在圖中试躏,左邊是非并行GC的執(zhí)行過程,而右邊是并行GC的執(zhí)行過程泣刹。它們的總體流程是相似的椅您,主要差別在于前者在執(zhí)行的過程中一直是掛起非GC線程的掀泳,而后者是有條件地掛起非GC線程。

第1步到第3步用于并行和非并行GC:

1.? 調(diào)用函數(shù)dvmSuspendAllThreads掛起所有的線程脑沿,以免它們干擾GC庄拇。

2.? 調(diào)用函數(shù)dvmHeapBeginMarkStep初始化Mark Stack丛忆,并且設(shè)定好GC范圍仍秤。

Mark Stack具體來說诗力,當(dāng)我們標(biāo)記完成根集對象之后苇本,就按照它們的地址從小到大的順序標(biāo)記它們所引用的其它對象瓣窄。假設(shè)有A、B裳凸、C和D四個(gè)對象姨谷,它的地址大小關(guān)系為A < B < C < D梦湘,其中捌议,B和D是根集對象禁灼,A被D引用轿曙,C沒有被B和D引用。那么我們將依次遍歷B和D穿铆。當(dāng)遍歷到B的時(shí)候荞雏,沒有發(fā)現(xiàn)它引用其它對象凤优,然后就繼續(xù)向前遍歷D對象蜈彼。發(fā)現(xiàn)它引用了A對象幸逆。按照遞歸的算法还绘,這時(shí)候除了標(biāo)記A對象是正在使用之外拍顷,還應(yīng)該去檢查A對象有沒有引用其它對象昔案,然后又再檢查它引用的對象有沒有又引用其它的對象,一直這樣遍歷下去。這樣就跟函數(shù)遞歸一樣呼伸。更好的做法是將對象A記錄在一個(gè)Mark Stack中括享,然后繼續(xù)檢查地址值比對象D大的其它對象铃辖。對于地址值比對象D大的其它對象娇斩,如果它們引用了一個(gè)地址值比它們小的其它對象犬第,那么這些其它對象同樣要記錄在Mark Stack中。等到該輪檢查結(jié)束之后丰介,再回過頭來檢查記錄在Mark Stack里面的對象哮幢。然后又重復(fù)上述過程橙垢,直到Mark Stack等于空為止钢悲。

3.? 調(diào)用函數(shù)dvmHeapMarkRootSet標(biāo)記根集對象莺琳。

第4到第6步用于并行GC:

4.? 調(diào)用函數(shù)dvmClearCardTable清理Card Table惭等。Card Table由Card組成辞做,一個(gè)Card實(shí)際上就是一個(gè)字節(jié)秤茅,它的值要么是CLEAN框喳,要么是DIRTY厦坛。因?yàn)榻酉聛砦覀儗?huì)喚醒第1步掛起的線程杜秸。并且使用這個(gè)Card Table來記錄那些在GC過程中被修改的對象撬碟。

5.? 調(diào)用函數(shù)dvmUnlock解鎖堆。這個(gè)是針對調(diào)用函數(shù)dvmCollectGarbageInternal執(zhí)行GC前的堆鎖定操作稼钩。

6.? 調(diào)用函數(shù)dvmResumeAllThreads喚醒第1步掛起的線程坝撑。

第7步用于并行和非并行GC:

7.? 調(diào)用函數(shù)dvmHeapScanMarkedObjects從第3步獲得的根集對象開始巡李,歸遞標(biāo)記所有被根集對象引用的對象侨拦。

第8步到第11步用于并行GC:

8.? 調(diào)用函數(shù)dvmLockHeap重新鎖定堆狱从。這個(gè)是針對前面第5步的操作季研。

9.? 調(diào)用函數(shù)dvmSuspendAllThreads重新掛起所有的線程与涡。這個(gè)是針對前面第6步的操作驼卖。

10. 調(diào)用函數(shù)dvmHeapReMarkRootSet更新根集對象酌畜。因?yàn)橛锌赡茉诘?步到第6步的執(zhí)行過程中檩奠,有線程創(chuàng)建了新的根集對象。

11. 調(diào)用函數(shù)dvmHeapReScanMarkedObjects歸遞標(biāo)記那些在第4步到第6步的執(zhí)行過程中被修改的對象蕉扮。這些對象記錄在Card Table中喳钟。

第12步到第14步用于并行和非并行GC:

12. 調(diào)用函數(shù)dvmHeapProcessReferences處理那些被軟引用(Soft Reference)奔则、弱引用(Weak Reference)和影子引用(Phantom Reference)引用的對象易茬,以及重寫了finalize方法的對象抽莱。這些對象都是需要特殊處理的食铐。

13. 調(diào)用函數(shù)dvmHeapSweepSystemWeaks回收系統(tǒng)內(nèi)部使用的那些被弱引用引用的對象虐呻。

14. 調(diào)用函數(shù)dvmHeapSourceSwapBitmaps交換Live Bitmap和Mark Bitmap斟叼。執(zhí)行了前面的13步之后犁柜,所有還被引用的對象在Mark Bitmap中的bit都被設(shè)置為1洲鸠。而Live Bitmap記錄的是當(dāng)前GC前還被引用著的對象。通過交換這兩個(gè)Bitmap馋缅,就可以使得當(dāng)前GC完成之后扒腕,使得Live Bitmap記錄的是下次GC前還被引用著的對象。

第15步和第16步用于并行GC:

15. 調(diào)用函數(shù)dvmUnlock解鎖堆萤悴。這個(gè)是針對前面第8步的操作瘾腰。

16. 調(diào)用函數(shù)dvmResumeAllThreads喚醒第9步掛起的線程。

第17步和第18步用于并行和非并行GC:

17. 調(diào)用函數(shù)dvmHeapSweepUnmarkedObjects回收那些沒有被引用的對象蹋盆。沒有被引用的對象就是那些在執(zhí)行第14步之前,在Live Bitmap中的bit設(shè)置為1硝全,但是在Mark Bitmap中的bit設(shè)置為0的對象栖雾。

18. 調(diào)用函數(shù)dvmHeapFinishMarkStep重置Mark Bitmap以及Mark Stack。這個(gè)是針對前面第2步的操作伟众。

第19步用于并行GC:

19. 調(diào)用函數(shù)dvmLockHeap重新鎖定堆析藕。這個(gè)是針對前面第15步的操作。

第20步用于并行和非并行GC:

20. 調(diào)用函數(shù)dvmHeapSourceGrowForUtilization根據(jù)設(shè)置的堆目標(biāo)利用率調(diào)整堆的大小凳厢。

第21步用于并行GC:

21. 調(diào)用函數(shù)dvmBroadcastCond喚醒那些等待GC執(zhí)行完成再在堆上分配對象的線程账胧。

第22步用于非并行GC:

22. 調(diào)用函數(shù)dvmResumeAllThreads喚醒第1步掛起的線程竞慢。

第23步用到并行和非并行GC:

23. 調(diào)用函數(shù)dvmEnqueueClearedReferences將那些目標(biāo)對象已經(jīng)被回收了的引用對象增加到相應(yīng)的Java隊(duì)列中去,以便應(yīng)用程序可以知道哪些引用引用的對象已經(jīng)被回收了治泥。


5.進(jìn)程與線程管理

Dalvik虛擬機(jī)運(yùn)行在Linux操作系統(tǒng)之上筹煮。我們知道,Linux操作系統(tǒng)并沒有純粹的線程概念居夹,只要兩個(gè)進(jìn)程共享同一個(gè)地址空間败潦,那么就可以認(rèn)為它們同一個(gè)進(jìn)程的兩個(gè)線程。Linux操作系統(tǒng)提供了兩個(gè)fork和clone兩個(gè)調(diào)用吮播,其中变屁,前者就是用來創(chuàng)建進(jìn)程的,而后者就是用來創(chuàng)建線程的意狠。

Dalvik虛擬機(jī)線程的創(chuàng)建過程

5.1Thread.start

Thread類的成員函數(shù)start首先檢查成員變量hasBeenStarted的值是否等于true粟关。如果等于true的話,那么就說明當(dāng)前正在處理的Thread對象所描述的Java線程已經(jīng)啟動(dòng)起來了环戈。一個(gè)Java線程是不能重復(fù)啟動(dòng)的闷板,否則的話,Thread類的成員函數(shù)start就會(huì)拋出一個(gè)類型為IllegalThreadStateException的異常院塞。通過了上面的檢查之后遮晚,Thread類的成員函數(shù)start接下來就繼續(xù)調(diào)用VMThread類的靜態(tài)成員函數(shù)create來創(chuàng)建一個(gè)線程。

5.2VMThread.create

VMThread類的靜態(tài)成員函數(shù)create是一個(gè)JNI方法拦止,它將Java層傳遞過來的參數(shù)獲取出來之后县遣,就調(diào)用另外一個(gè)函數(shù)dvmCreateInterpThread來執(zhí)行創(chuàng)建線程的工作。

5.3dvmCreateInterpThread

將用來描述新創(chuàng)建的Dalvik虛擬機(jī)線程的Native層的Thread對象保存在gDvm.threadList所描述的一個(gè)線程列表中汹族,這是因?yàn)楫?dāng)前所有Dalvik虛擬機(jī)線程都保存在這個(gè)列表中萧求。

將新創(chuàng)建的Dalvik虛擬機(jī)線程的狀態(tài)設(shè)置為THREAD_VMWAIT,使得新創(chuàng)建的Dalvik虛擬機(jī)線程繼續(xù)往前執(zhí)行顶瞒,這是因?yàn)樾聞?chuàng)建的Dalvik虛擬機(jī)線程將自己的狀態(tài)設(shè)置為THREAD_STARTING喚醒創(chuàng)建它的線程之后夸政,又會(huì)等待創(chuàng)建它的線程通知它繼續(xù)往前執(zhí)行。

5.4interpThreadStart

1. 調(diào)用函數(shù)prepareThread來初始化新創(chuàng)建的Dalvik虛擬機(jī)線程榴徐。

2. 將新創(chuàng)建的Dalvik虛擬機(jī)線程的狀態(tài)設(shè)置為THREAD_STARTING守问,以便其父線程,也就是創(chuàng)建它的線程可以繼續(xù)往前執(zhí)行坑资。

3. 通過一個(gè)while循環(huán)來等待父線程通知自己繼續(xù)往前執(zhí)行耗帕,也就是等待父線程將自己的狀態(tài)設(shè)置為THREAD_VMWAIT。

4. 調(diào)用函數(shù)dvmCreateJNIEnv來為新創(chuàng)建的Dalvik虛擬機(jī)線程創(chuàng)建一個(gè)JNI環(huán)境袱贮。

5. 調(diào)用函數(shù)dvmChangeStatus將新創(chuàng)建的Dalvik虛擬機(jī)線程的狀態(tài)設(shè)置為THREAD_RUNNING仿便,表示它正式進(jìn)入運(yùn)行狀態(tài)。

6. 如果此時(shí)gDvm.debuggerConnected的值等于true,那么就說明有調(diào)試器連接到當(dāng)前Dalvik虛擬機(jī)來了探越,這時(shí)候就調(diào)用函數(shù)dvmDbgPostThreadStart來通知調(diào)試器新創(chuàng)建了一個(gè)線程。

7. 調(diào)用函數(shù)dvmChangeThreadPriority來設(shè)置新創(chuàng)建的Dalvik虛擬機(jī)線程的優(yōu)先級窑业,這個(gè)優(yōu)先級值保存在用來描述新創(chuàng)建的Dalvik虛擬機(jī)線程的一個(gè)Java層Thread對象的成員變量priority中钦幔。

8. 找到Java層的java.lang.Thread類的成員函數(shù)run,并且通過函數(shù)dvmCallMethod來交給Dalvik虛擬機(jī)解釋器執(zhí)行常柄,這個(gè)java.lang.Thread類的成員函數(shù)run即為Dalvik虛擬機(jī)線程的Java代碼入口點(diǎn)函數(shù)鲤氢。

9. 從函數(shù)dvmCallMethod返回來之后,新創(chuàng)建的Dalvik虛擬機(jī)線程就完成自己的使命了西潘,這時(shí)候就可以調(diào)用函數(shù)dvmDetachCurrentThread來執(zhí)行清理工作卷玉。

6.Dalvik部分源碼分析


start指令對應(yīng)的代碼

jni_invocation.Init:初始化JNI相關(guān)的幾個(gè)重要函數(shù)。通過dlopen加載libdvm.so喷市∠嘀郑看來每個(gè)Java進(jìn)程都會(huì)有這個(gè)東西。這可是dalvik vm的核心庫品姓。這個(gè)庫有很多API寝并,我個(gè)人覺得如果了解libdvm.so的話,應(yīng)該能干很多事情腹备。這里就不講那么仔細(xì)了衬潦。

startVm:注意,它傳入了一個(gè)JNIEnv* env對象進(jìn)去植酥,當(dāng)這個(gè)函數(shù)返回時(shí)镀岛,我們在JNI中天天見的JNIEnv對象就是這個(gè)東西。startVm是Dalvik VM的核心友驮,該函數(shù)返回后漂羊,VM就基本就緒了。其實(shí)startVm方法做的事情就是初始化VM核心數(shù)據(jù)結(jié)構(gòu)喊儡。講一下跟目前有相關(guān)的知識點(diǎn)拨与,實(shí)際上,根據(jù)Java VM規(guī)范艾猜,類的唯一性由全路徑類名+定義它的ClassLoader兩者唯一確定买喧。

startReg:注冊Android平臺(tái)中一些特有的JNI函數(shù)。有興趣的可以深入研究匆赃。

?
dvmStartup指令對應(yīng)的代碼

dvmStartup函數(shù)是在startVm函數(shù)內(nèi)的虛擬機(jī)創(chuàng)建的核心淤毛。

dvmStartup首先是解析參數(shù),這些參數(shù)信息可能會(huì)傳給gDvm相關(guān)的成員變量算柳。解析參數(shù)是由setCommandLineDefaults和processOptions來完成的低淡。代碼就不看了,就講幾個(gè)關(guān)鍵參數(shù)。

gDvm.executionMode = kExecutionModeJit:如果定義的WITH_JIT宏蔗蹋,則執(zhí)行模式是JIT模式何荚。

gDvm.bootClassPathStr:由BOOTCLASSPATH環(huán)境變量提供。講一下BOOTCLASSPATH值指向是什么猪杭,system/framework下幾乎所有的jar包都被放在了BOOT CLASSPATH里餐塘。

gDvm.mainThreadStackSize = kDefaultStackSize。kDefaultStackSize值為16K皂吮,代表主線程的堆棧大小

gDvm.dexOptMode = OPTIMIZE_MODE_VERIFIED戒傻,用于控制odex操作,該參數(shù)表示只對verified的類進(jìn)行odex蜂筹。

接下來一堆startup函數(shù)中的重點(diǎn)需纳,dvmClassStartup函數(shù)

dvmClassStartup函數(shù)相應(yīng)的代碼

先講一下dvmClassStartup函數(shù)做成了什么事情:

創(chuàng)建了一個(gè)Hash表,用來存儲(chǔ)已經(jīng)加載的類艺挪。

創(chuàng)建了代表java.lang.Class和所有基礎(chǔ)數(shù)據(jù)類型的Class信息不翩。

processClassPath這個(gè)函數(shù),它要加載所有的Boot Class闺属,它涉及到system/framework/下的jar包的加載慌盯,加載完畢后,虛擬機(jī)啟動(dòng)的流程差不多就完了掂器。

接下來講的是Class的加載和初始化:

new-instance指令對應(yīng)的代碼

先調(diào)用dvmDexGetResolvedClass亚皂,看看目標(biāo)類TestAnother是不是已經(jīng)被解析過了。前面曾經(jīng)提到說国瓮,一個(gè)類在初始化的時(shí)候可能會(huì)解析它所使用到的其他類灭必。

假設(shè)被引用的類沒有解析過,則調(diào)用dvmResolveClass來加載目標(biāo)類乃摹。

目標(biāo)類加載成功后禁漓,如果該類沒有初始化過,則調(diào)用dvmInitClass進(jìn)行初始化孵睬。

dvmResolveClass其主要邏輯就是先得到目標(biāo)類名(Lcom/test/TestAnother;)然后調(diào)用dvmFindClassNoInit來加載目標(biāo)類播歼。

dvmFindClassNoInit其主要邏輯就是由于referrer的ClassLoader(也就是使用TestAnother類的TestMain類的ClassLoader)不為空,代碼邏輯將走到findClassFromLoaderNoInit掰读。

findClassFromLoaderNoInit其主要邏輯就是調(diào)用java/lang/ClassLoader的loadClass函數(shù)來加載類秘狞。

加載成功后,接下來就是初始化了蹈集、dvmInitClass從函數(shù)名就能知道它的作用了烁试。

dvmInitClass函數(shù)對應(yīng)的代碼

這只是Dalvik虛擬機(jī)學(xué)習(xí)之路的一個(gè)簡易整理版本,如果你想深入學(xué)習(xí)Dalvik虛擬機(jī)拢肆,這些內(nèi)容還是不夠的减响。還有很多東西并沒有講到靖诗,還需要大家繼續(xù)努力。

參考地址:

http://www.infoq.com/cn/articles/android-in-depth-dalvik?utm_source=infoq&utm_campaign=user_page&utm_medium=link

http://blog.csdn.net/luoshengyang/article/details/8852432

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末支示,一起剝皮案震驚了整個(gè)濱河市刊橘,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌颂鸿,老刑警劉巖伤为,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異据途,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)叙甸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進(jìn)店門颖医,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人裆蒸,你說我怎么就攤上這事熔萧。” “怎么了僚祷?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵佛致,是天一觀的道長。 經(jīng)常有香客問我辙谜,道長俺榆,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任装哆,我火速辦了婚禮罐脊,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蜕琴。我一直安慰自己萍桌,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布凌简。 她就那樣靜靜地躺著上炎,像睡著了一般。 火紅的嫁衣襯著肌膚如雪雏搂。 梳的紋絲不亂的頭發(fā)上藕施,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天,我揣著相機(jī)與錄音畔派,去河邊找鬼铅碍。 笑死,一個(gè)胖子當(dāng)著我的面吹牛线椰,可吹牛的內(nèi)容都是我干的胞谈。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼烦绳!你這毒婦竟也來了卿捎?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤径密,失蹤者是張志新(化名)和其女友劉穎午阵,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體享扔,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡底桂,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了惧眠。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片籽懦。...
    茶點(diǎn)故事閱讀 39,690評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖氛魁,靈堂內(nèi)的尸體忽然破棺而出暮顺,到底是詐尸還是另有隱情,我是刑警寧澤秀存,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布捶码,位于F島的核電站,受9級特大地震影響或链,放射性物質(zhì)發(fā)生泄漏惫恼。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一澳盐、第九天 我趴在偏房一處隱蔽的房頂上張望尤筐。 院中可真熱鬧,春花似錦洞就、人聲如沸盆繁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽油昂。三九已至,卻和暖如春倾贰,著一層夾襖步出監(jiān)牢的瞬間冕碟,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工匆浙, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留安寺,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓首尼,卻偏偏與公主長得像挑庶,于是被迫代替她去往敵國和親言秸。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容