一、簡介
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框架層已經設定過了。