看板 AndroidDev 關於我們 聯絡資訊
二進制組合指令應該是指機械碼 (machine code), 雖然電腦上哪有什麼東西背後不是二進制的。 另外這也是一個最好看原文書的例子,中文翻譯常會這樣,沒有個規範。 JIT 在我學習的時候,在教科書上的定義就有點模糊。 基本上它只需要符合它的名字 just-in-time compilation 即可。 也就是說只要 compile 是發生在 runtime 或說 runtime 能夠同時 compile 就是 JIT。 在回答剩下的問題前,我覺得應該瞭解一下 machine code、bytecode、source code 和 compiler、interpreter,用 bottom-up 的角度來看這些問題。 想想看,假設你寫了一支程式,它可以用你自訂的文本作為輸入來決定程式的行為。 譬如說你寫了一支按鍵精靈,現在有一文本如下: click 3 move 100 200 假設這個文本第一行表示按左鍵 3 下,第二行是把滑鼠游標移到座標 (100, 200)。 你的程式要能處理,可能會有個這樣的判斷式: // line == "click 3" or "move 100 200" cmd = line.substring(0, line.indexOf(' ')); opt = line.substring(line.indexOf(' ') + 1); switch (cmd) { case "click": for (int i = 0; i < Integer.parseInt(opt); i++) do_click(); break; case "move": // move to (x, y) break; // something else } 假設你自定的文本可以很彈性,彈性到像是一個程式語言,那它就是一個程式語言, 既然是程式語言,這個文本也可以被稱之為 source code。 而你寫的這支程式,能夠解析並運行這個語言,那麼這支程式就是一個 interpreter。 到這邊都很完美,可是也許有一天你想要讓程式跑得更快。 假設 interpreter 已經是 machine code,那麼要加速的話也許會把頭腦動到優化文本。 但是文本已經是一個很好寫的語言了,你可能不想隨易地更動, 所以一個可行的方法是在 interpreter 讀取前,先對文本做處理, 把文本轉成更能有效率被執行的樣子。 這個動作可以被稱為 data pre-processing,不過這邊也可以叫做 compiling, 因為這個 data 是程式語言。 沒人規定 compile 過後的東西一定得是 machine code 吧? 所以我們 compile 成比較有效率的樣子, 然後自己替 compile 後的文本取個名字叫 bytecode, 聽起來很有氣勢,跑起來很快,沒有 bug,豈不快哉? Bytecode 會長什麼樣子呢? click click click move 100 200 假設會長上面這個樣子,那 interpreter 也要改一下: switch (cmd) { case "click": do_click(); break; case "move": // move to (x, y) break; // something else } 注意,拿掉了 for loop。 這只是個範例所以很簡單,不過不可否認的,interpreter 的確更快了。 Byte code、source code、compiler、interpreter 我們都有了, 接下來想要更快,該怎麼做? 既然 source code 能轉成 byte code, 當然也能想法辦把 byte code 轉成 machine code。 可是想想,不太對,如果 source code 能直接被轉成 machine code, 那就可以直接 run 了啊!還要 interpreter 幹嘛? 所以你決定把 interpret byte code 分成兩個階段, 第一個階段是解析它,第二個階段是把它轉成 machine code, 然後跳到這段 machine code 執行。 switch (cmd) { case "click": { address 12345678 mov 123 jump 123 } { call 12345678 } break; case "move": // move to (x, y) break; // something else } 組語我不會寫,我們就假裝 12345678 是一個 memory address, 這個 address 裡面裝了 do_click() 這個 function, 這個例子雖然可能不會真的加速, 不過如果 byte code 的樣子再複雜一點, 轉成 machine code 後的執行效能就會顯現出來。 當然這段 machine code 用過後可以不要馬上丟掉,先 cache 住, 下次要用再跳過去,不必重轉一次,速度就又更快了。 到這邊,應該可以看出來,這和省不省電沾不上邊,所以我們先忽略那個問題。 再來,interpreter、compiler 都是你寫的,要在執行的同時, 先一次把 source code 全 compile 成 machine code 再執行, 還是要 interpret 到哪就 compile 到哪,都視你的實作而定。 當然在執行的同時才開始把整份 source code compile 成 machine code, 可能是沒有意義的,因為若要這樣那幹嘛不先 compile 好, JIT 可是在每一次執行 program,把 program 變成 process 時都要來一次的, 所以如果真的要這樣做的話,應該不會留到 runtime 才做。 版本 1 和 2 基本上不衝突。你可以每執行到一行 byte code, 就先把它變成 machine code 並 cache 住再執行,這樣就算是以原生的方式在跑了。 希望有提供到一些方向。 ※ 引述《gn00618777 (非常念舊)》之銘言: : ※ 引述《gn00618777 (非常念舊)》之銘言: : : 我查詢了網路上以及書本 : : 版本1: JIT是將source code 轉換成 byte code之後,在程式執行期間 : : 再將byte code編譯成機械碼。 : : 版本2: 擁有JIT表示Dalvik將APP的byte code轉換成二進制組合指令,那將 : : 以原生方式執行在目標的CPU上,而不是由VM一次解譯一條指令。 : : 這兩者,哪種比較對阿.....版本1說得好像就是執行期間,需要才編譯成機械碼。 : : 這和版本2是直接說"不是由VM一次解譯一條指令"好像有點抵觸,希望能為我解惑, : : 謝謝。版本2出自於O'REILY翻譯的書,我個人覺得翻譯的好爛,前因後果要自己兜起來。 : 我還是不太懂版本二.. : "不是由VM一次解譯一條指令",意思是說不是在執行中需要才編譯? : 是說JIT已經在執行前將APP byte code編譯成機械碼了嗎?這樣在執行前 : 是不是不用佔用CPU來編譯比較省電? : 這是我的理解,希望有神人為我補充...謝謝。 -- http://changyuheng.github.io/ -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 220.141.121.217 ※ 文章網址: http://www.ptt.cc/bbs/AndroidDev/M.1408728443.A.17F.html ※ 編輯: changyuheng (220.141.121.217), 08/23/2014 01:32:00
tac0wu: 板主 半夜生好文 真有心 推~ 08/23 01:37
changyuheng: 這篇已經被高手點名有錯誤,在修正前請先不要全盤 08/23 16:35
changyuheng: 接受。 08/23 16:35
gn00618777: 樓上是神>////< 08/27 15:23