Re: [问题] JIT 问题

楼主: changyuheng (张昱珩)   2014-08-23 01:27:20
二进制组合指令应该是指机械码 (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来编译比较省电?
: 这是我的理解,希望有神人为我补充...谢谢。
作者: tac0wu (在BBS中流浪)   2014-08-23 01:37:00
板主 半夜生好文 真有心 推~
楼主: changyuheng (张昱珩)   2014-08-23 16:35:00
这篇已经被高手点名有错误,在修正前请先不要全盘接受。
作者: gn00618777 (非常念旧)   2014-08-27 15:23:00
楼上是神>////<

Links booklink

Contact Us: admin [ a t ] ucptt.com