天天看點

Dalvik——如何控制vm

 一、簡介

         Dalvik虛拟機支援一系列的指令行參數(使用adbshell dalvikvm –help擷取清單),但是不可能通過android應用運作時來傳遞任意參數,但是可以通過特定的系統參數來影響虛拟機行為。

         對于下述所有參數,你都可以通過setprop來設定系統特性,shell指令如下:

adbshell setprop <name> <value>

         必須重新開機android運作時進而使得改變生效(adb shell stop:adb shell start)。這是因為,這些設定在zygote程序中處理,而zygote最早啟動并且永遠存活。

         你不可以以無特權使用者的身份設定dalvik.*參數及重新開機系統。你可以在使用者調試版本的shell上使用adb root或者運作su指令來擷取root權限,如有疑問,

adbshell getprop <name>

         可以告訴你setprop是否發生。

         如果你不想在裝置重新開機之後特性消失,在/data/local.prop上加一行:

<name>= <value>

         重新開機之後這樣的改變也會一直存在,但是如果data分區被擦除了就消失了。(提示:在工作台上建立一個local.prop,然後adb push local.prop /data/,或者,使用類似于adb shell “echo name =value >> /data/local.prop”的指令——注意,引号很重要)

二、擴充的JNI檢測         JNI(Java Native Interface),java本地接口,提供了java語言程式調用本地(C/C++)代碼的方法。擴充的JNI檢測會引起系統運作更慢,但是可以發現一系列的讨厭的bug,防止他們産生問題。         有兩個系統參數影響這個功能,這個功能可以通過-Xcheck:jni指令行參數來激活。第一個參數是ro.kernel.android.checkjni,這是通過android編譯系統對development的編譯來設定的(也可以通過android模拟器設定,除非通過模拟器指令行置了-nojni标志位)。因為這是一個”ro.”特性,裝置啟動之後參數就不能變了。         為了能觸發CheckJNI标志位,第二種特性是dalvik.vm.checkjni,它的值覆寫了ro.kernel.android.checkjni的值。         如果這個特性沒有被定義,dalvik.vm.checkjni也沒有設定成false,那麼-Xcheck:jni标志位就沒有傳入,JNI檢測也就沒有使能。         要打開JNI檢測,使用以下指令:adbshell setprop dalvik.vm.checkjni true。         也可以通過系統特性将JNI檢測選項傳遞給虛拟機,dalvik.vm.jniopts的值可以通過-Xjniopts參數傳入,例如:adb shellsetprop dalvik.vm.jniopts forcecopy         更多資訊見JNI建議。 三、斷言         dalvik虛拟機支援java程式設計語言的斷言表達式,預設它是關閉的,但是可以通過-ea參數的方式(dalvikvm –ea …..)設定dalvik.vm.enableassertions特性。         在其他桌面虛拟機中這個參數同樣生效,通過提供class名、package名(後跟“…”),或者特殊值“all”。例如:adbshell setprop dalvik.vm.enableassertion all就可以在所有非系統class中使能斷言。         這個系統特性比全指令行更受限制,不可以通過-ea入口設定更多,而且沒有指定-da入口的方法,而且未來也沒有-esa/-dsa等價的東西。 四、位元組碼校驗和優化         系統嘗試預校驗dex檔案中的所有類,進而降低class的負擔,進而可以使用一系列的優化來提升運作性能。這些都是通過dexopt指令來實作的,不論是在編譯系統中還是在安裝上。在開發裝置上,dexopt可能在dex檔案第一次被使用時運作,而不論它或者它的依賴是否更新過(Just-in-time優化和校驗,JIT)。         有兩個指令行标志位控制JIT優化和校驗,-Xverify和-Xdexopt。andorid架構基于dalvik.vm.dexopt-flags特性來配置這倆參數,如果你設定:adbshell setprop dalvik.vm.dexopt-flags v=a o=v         那麼android架構會将-Xverify:all-Xdexopt:verified傳遞給虛拟機,這将使能校驗并且隻優化校驗成功的class。這是最安全的設定,也是預設的。         你也可以設定dalvik.vm.dexopt-flags v=n使得架構傳輸-Xverify:none –Xdexopt:verified進而不使能校驗(我們可以傳輸-Xdexopt:all進而允許優化,但是這并不能優化更多代碼,因為沒有通過校驗的class可能被優化器以同樣的理由跳過)。這時class不會被dexopt校驗,而沒被校驗的代碼很大難以執行。         使能校驗會使得dexopt指令明顯花費更多時間,因為校驗過程相對較慢,一旦校驗和優化過的dex檔案準備就緒,校驗就不會占用額外的開銷除非在加載預校驗失敗的class。         如果你的dex檔案的校驗關閉了,而後來又打開了校驗器,應用加載會明顯變慢(大概40%以上)因為class會在第一次被調用的時候校驗。         為了最佳效果,當特性變化的時候你應該為dex檔案強制重新調用dexopt,即:adbshell “rm /data/dalvik-cache/*”         它删除了暫存的dex檔案,記住要中止再打開運作時(adb shell stop:adb shell start)。(老的運作時版本支援布爾型的dalvik.vm.verify-bytecode特性,但是被dalvik.vm.dexopt-flags替代了) 五、運作模式目前dalvik vm的實作包括三個獨立的解釋核心:“快速”(fast)、“可移植”(portable)、“調試”(debug)。快速解釋器是為目前平台優化的,可能包括手動優化的彙編檔案;相對的,可移植解釋器是用C寫的,可在廣泛的平台上使用;調試解釋器是可移植解釋器的變種,包括了支援程式分析(profiling)和單步。vm可能也支援just-in-time編譯,嚴格的說它并不是另一個解釋器,JIT編譯器也可以被同樣的标志位使能/不使能(檢視dalvik –help的輸出資訊來檢視JIT編譯器是否在你的虛拟機裡面使能)。

vm允許你在快速、可移植和jit中選擇,通過使用-Xint參數的擴充來實作,該參數的值可以通過dalvik.vm.execution-mode系統特性來設定。為了選擇可移植解釋器,你應該用:

adb shell setpropdalvik.vm.execution-mode int:portable

如果該參數沒有指定,系統會自動選擇最合适的編譯器,有時候機器可能允許選擇其他模式,例如jit編譯器。不是所有的平台都有優化的實作,有時候,快速編譯器是由一系列的c實作的,這個結果會比可移植編譯器還慢(當我們對所有流行平台都有優化版本的時候,這個命名“快速”就更準确了)。如果程式分析使能或者調試器連接配接了,vm會變為調試解釋器。當程式分析結束或者調試器中斷連接配接,就會恢複原來的解釋器。(用調試解釋器會明顯變慢,這是在評估資料時要記住的)JIT編譯器可以通過在應用程式AndroidManifest.xml中加入android:vmSafeMode=”true”來不使能,你懷疑JIT編譯器會使得你的應用運作不正常的時候可以使用。 六、死鎖預測         如果虛拟機以WITH_DEADLOCK_PREDICTION參數編譯,那麼死鎖預測器會在-Xdeadlockpredict參數中使能。(dalvikvm –help會告訴你虛拟機是否編譯正确——在Configured中按行查找deadlock_prediction)這個特性會讓虛拟機一直跟蹤對象的鎖擷取的順序,如果程式試圖以與之前看到不同的順序擷取一些鎖,虛拟機會log一個warning并有選擇的抛出異常。         指令行參數是基于dalvik.vm.deadlock-predict特性設定的,正确的值是off表示不使能它(預設),warn表示log問題但是繼續執行,err表示從monitor-enter指令中引發一個dalvik.system.PotentialDeadlockError異常,abort表示終止整個虛拟機。         你通常可以這麼使用:adbshell setprop dalvik.vm.deadlock-predict err         除非你可以在log資訊滾動的時候一直關注着。         注意這個特性是死鎖預測,不是死鎖檢測——在目前實作中,在鎖被擷取之後才會進行計算(這減輕了代碼,降低了互斥資訊外的備援)。在挂起的程序中執行kill -3時可以發現一個死鎖,并且可以在log資訊中檢測到。         這僅僅考慮了監督程式,本地的互斥量和其他資源也會引起死鎖,而且不會被它檢測到。 七、dump堆棧追蹤         和其他桌面虛拟機一樣,dalvik虛拟機收到SIGQUIT(Ctrl-\ 或者kill -3)時,會為所有的現成dump所有的堆棧追蹤。它預設寫入Android 的log,但是也可以寫入一個檔案。         dalvik.vm.stack-trace-file特性允許你指定要将線程堆棧追蹤寫入的檔案名,如果不存在,将建立,新的資訊将追加到檔案尾,檔案名通過-Xstacktracefile參數寫入虛拟機。例如:adbshell setprop dalvik.vm.stack-trace-file /tmp/stack-traces.txt         如果這個特性沒有被定義,虛拟機會在收到這個信号時将堆棧追蹤資訊寫入android log。 八、dex檔案和校驗         出于性能考慮,優化過的dex檔案的和校驗被取消了,這通常叫安全,因為檔案是在裝置上産生的,并且有禁止修改的權限。         但是如果裝置的存儲器不可靠,就會發生資料損壞,這通常表現為重複的虛拟機崩潰。為了快速診斷這種失敗,虛拟機提供了-Xcheckdexsum參數,如果設定了,在内容被使用之前所有的dex檔案都會進行和校驗。         如果dalvik.vm.check-dex-sum特性被使能,那麼應用架構會在虛拟機建立時提供這個參數。         為了使能額外的dex和校驗,可以:adbshell setprop dalvik.vm.check-dex-sum true         不正确的和校驗會組織dex資料的使用,産生錯誤并寫入log檔案,如果裝置曾經有過這樣的問題,那麼将這個特性寫入/data/local.prop很有用。         注意dexdump工具每次都會進行dex和校驗,它也可以用于檢測大量的檔案。 九、産生标志位         在“Honeycomb”版本中引入了一系列的彙編,它們通過标志位寫入虛拟機:adb shell setprop dalvik.vm.extra-opts “flag1flag2 … flagN”         這些标志位之間用空格隔開。你可以指定任意多的标志位隻要它們在系統特性值的長度範圍内(目前是92個字元)。         這些額外的标志位會被加到指令行的底端,意味着它們會覆寫之前的設定。這些可以用于例如測試不同的-Xmx的值即使android架構層已經設定過了。

 -----------------------------------------------

jni check的方法,可以對非法的jni調用做check, 

在/data/local.prop裡加上dalvik.vm.checkjni=true, 然後重新開機

如果沒有/data/local.prop檔案則自己建立一個放進去