2009年12月17日 星期四

初探JIT compiler 與 Android Dalvik VM

筆者之前有研究過CDC VM (藍光播放器中的Java VM),是SUN的RI (參考實作版),從interperter, JIT compiler到GC都有看過原始碼, 最近也在看Android的Dalvik VM,以下有一些心得跟大家分享。
當然筆者的程度還很弱,不及許多已在Android或embedded system打滾多年的高手,但希望藉由以下的淺顯說明可以讓初階學習者了解JITcompiler 與 VM 的關係。

1. Java的效能比較差嗎?

很多人都把runtime的效能當作絕對比較指標,但是他們常常忽略到的是軟體開發的彈性與速度,在Java中透過標準API寫出一個類似MSN的聊天軟體(UI, data persistence, TCP/IP socket....etc)可能只需要N倍時間,但用C/C++可能需要3N甚至到10N以上的時間。

另外,現在能從SUN網站上download的JVM,都搭載了Just-In-Time compiler,這是一種動態Java method compiler,以Java method (A.doSomeThing())為單位,能夠動態的在程式執行時根據熱門程度編譯成機器碼(存至code cache)或只是直譯某個Java method,所以Sun也使用 "Hot Spot" VM作為產品名稱

所以,其實在JIT compiler的實作持續改進下,Java的程式執行效能已經近乎執行機器碼相同的速度。還以為Java執行效能比較差的人,其實已經落伍至少兩至三年以上

現在Sony PS3, HTC Magic/Hero裡,其實都有虛擬機器VM的足跡。(PS3 使用IBM的CDC VM)

2. Android裡的VM效能如何?

首先,Android裡的VM不能稱為JVM,因為整個軟體開發框架中,Java只存在於程式寫作階段,在deploy階段就已經被dx這個tool,把.class轉換成.dex,這是一種特殊的binary格式,類似class,但是其有更先進的設計架構。

Android的VM稱為Dalvik VM,它只執行.dex檔,並且搭配Zygote(Android OS中的process管理器,其會preload所有的系統library,每個獨立的Android程式有各自的process,但卻可以share同一份library,例如android.os.*,這樣可以節省runtime記憶體),以系統化的方式整合進Linux系統,因此DalvikVM相較於Sun實作的CDC/CLDC VM,有著更節省記憶體的優勢,這樣間接的讓整體系統運作速度變快很多。

此外,很有趣的是,當Sun不斷的以JIT為核心,甚至在CLDC VM中也有JIT時,Dalvik VM在第一時間卻不使用JIT技術。(註:Android 2.0 的dalvik已經有JIT implementation, for ARM)

原因無他,也是因為記憶體。

JIT compiler,就是compiler,其編譯bytecode(8位元指令)轉換為機器碼(16, 32 or 64位元指令),這對於整體native code size是增加的,因此JIT compiler其實在嵌入式系統裡的記憶體使用量反而是增加的且間接的造成運作效能下降。因此DalvikVM只使用Intepreter作為bytecode execution engine。

什麼,這樣用intepreter不是更慢?

現在有試用過HERO的人就知道,其順暢程度直逼iPhone 3G,其原因就是其利用Java programming API與JNI的優勢,把常使用的功能切出來,盡量使用JNI直接用C/C++實作,再包裝成Java API,提供AP實作使用,例如Camera, GPS, Telephony, UI等API,因此Android程式一開始的進入點是interpreter執行沒錯,但到後期幾乎都是native code在運作。透過API隔開耗時與較不穩定的功能邏輯,AP實作者與系統廠各自分責,所以Android程式/OS的效能與一般也具有多工背景執行的OS相比,穩定且快速許多。

總結

對Android解決了嵌入式 Java VM傳統的問題,但卻延展了Java的優點,並且以優異的SDK為核心,統一了整個device/AP/market供應鏈,對大家皆有利益。

當然Android也有許多缺點,例如

  1. Android Framework版本持續變動,讓AP開發者必須經常變動API的使用方式。
  2. Android Low Memory Killer號稱可以自動回收process,但實際上user還是需要手動砍,才能順暢使用
  3. APK的DRM問題目前只有Google自己有解決方案,若有其他人想做第三方market,DRM問題依舊存在,因為只用AP層解決安全性較低。

2009年8月7日 星期五

Browser download function in Android


最近在開發有關於檔案傳輸的Android程式,突然心血來潮去看Android Framework內建的瀏覽器下載功能是如何進行設計的,看過原始碼才知道,其完全遵守MVC原則,縱使只是一個單純的下載工具。

右邊的圖顯示了概略的關係,並沒有使用正規UML,請多多包涵。

現在就從DownloadService開始吧


一 - 下載工作執行 (Control)

classes:
com.android.providers.downloads.DownloadReceiver
com.android.providers.downloads.DownloadService
com.android.providers.downloads.DownloadService.UpdateThread
com.android.providers.downloads.DownloadThread

實際上執行檔案下載的邏輯,其並無包含scheduling,任何task進來都是立即開始。

瀏覽器藉由新增DB record來觸發下載工作,DownloadService使用UpdateThread去monitor DB,若發現DB有需要處理的download工作,就會立刻new 出新的DownloadThread去handle實際的下載工作,並存有一份ArrayList (mDownloads)作為local memory cache

---------------------infinite for loop--------------------

1. 比對mDownloads與DB中的record
1-1. 若DB的record比mDownloads還多,則代表有新的工作,立刻開始新的下載
1-2. 若DB的record比mDownloads還少,則代表有工作已經被使用者從UI刪除,立刻停止並刪除該下載
2. 通知Notification bar目前的狀態 (請參照四 - UI - 顯示狀態於Notification bar (View))

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

DownloadThread並會把下載狀態透過ContentResolver/ContentProvider介面隨時 persistent至 SQLite DB (DownloadProvider) 裡


二 - 下載資訊persistence (Model, 橘色部分)

classes:
com.android.providers.downloads.DownloadProvider
(implements ContentProvider with SQLite DB)

儲存所有下載即時/歷史資訊的DB,其透過實作ContentProvider,可提供所有ap進行查詢

使用URI為 content://downloads/download
(android.provider.Downloads.CONTENT_URI)


三 - UI - 下載歷史資訊列表 (View)

classes:
com.android.browser.BrowserDownloadPage
com.android.browser.BrowserDownloadAdapter

當user點選menu中的下載歷史紀錄時,會顯示此Activity,其使用ListView + BrowserDownloadAdapter (繼承ResourceCursorAdapter,可方便透過Cursor介面撈DB中的資料並顯示於ListActivity中)

四 - UI - 顯示狀態於Notification bar (View)

classes:
com.android.providers.downloads.DownloadNotification

DownloadService內部有UpdateThread,其會定時更新Notification bar中的狀態 (ProgressBar, 下載百分比)


筆者之前寫過J2SE, J2ME BD-J等AP,在軟體架構上相較於Android可以發現,Android很重視 data persistence (Preferences, ContentProvider....etc)與XML modeling (UI, Animation, style....etc),這讓AP開發者可以花更多的時間在需要的事情上,而不用擔心資料儲存的複雜狀態與程序,以及UI或Animaiton等畫面細節的調整


2009年6月11日 星期四

讀後感: Android Dalvik VM vs. Java VM

在拜讀jserv大的此文章 Android Dalvik VM vs. Java VM 後,有一些感想

其實此專案點出一個重點,就是DalvikVM 的bytecode execution效能普遍沒有現有的CDC/CLDC VM來的好,
一方面是DalvikVM沒有JIT,一方面是發展的時間不夠久

當初DalvikVM不做JIT的原因是手持式裝置記憶體過小,太多的native code反而會造成記憶體管理上的負荷。
但是他們也認知到未來若Android porting至小筆電,JIT的需求會越來越明顯,因此DalvikVM JIT的確有放在DalvikVM的roadmap中

但反觀此專案的本質,他們讓Android app能夠透過此另類的middleware在任何的JavaVM上執行
我相信到後來他們一定會遇到一個困境:他們吸引不到大多數的programmer使用CLDC API撰寫Android app。

DalvikVM在整個Android system framework只是一個小小的部份,其他強大的系統特性與API才是重點,
  1. 所有的DalvikVM process皆由Zygote統籌管理並與DalvikVM合作,可以平行執行而不互相干擾
  2. 提供IBinder與AIDL方便撰寫IPC
  3. dex load進來後內容可以由各個process共享,而不像JavaVM每一個process有各自的class loader
  4. user可以一直開process而不需要提醒自己關閉,Low Memory Killer會主導與管理需要關閉的process,user永遠不會收到OOM (OutOfMemoryError)
  5. app可以在簡訊或來電時接到通知
  6. app可以控制手機上的 GPS, 發送簡訊, 甚至決定撥號與聯絡人操控介面
  7. app之間可以透過Intent 互通有無
Android能夠迅速在市場上竄紅,就是其系統化的思考,以及與AP層的緊密連結
而這個部份JavaVM永遠不可能做到,因為JavaVM永遠只是user space process。

他們終究不可能把Android整個系統與API、或者類似的功能放到手機上,
而DalvikVM會實作JIT是可預見的未來。

一點淺顯拙見,供大家參考。

2009年6月9日 星期二

Android : Low Memory Killer

Android DalvikVM不會丟出OOM的密技:就是直接砍掉你 Low Memory Killer

user在手機上使用時,會開很多的process,當然每一段時間只會使用一個主process,所以其實LMK會砍掉的是不常被使用或是背景的process,所以不會影響到user experience

比起一般JVM會於heap不夠時立刻丟出OOM,其實LMK的方式對使用者的影響反而比較小,因為使用者再也不用"關閉程式",系統會使用LMK來砍掉(也可以說幫忙關閉)舊的或不常使用的process

Android是一個重視user experience的OS,這就是為什麼Android比J2ME更適合用於消費性電子的手機上