我很好奇,为什么 Sun 决定让 JVM 堆栈为基础,而 Google 决定让 DalvikVM 以寄存器为基础?
我想JVM不能真正假设目标平台上有一定数量的寄存器可用,因为它应该是平台独立的。因此,它只是将寄存器分配等推迟到 JIT 编译器。 (如我错了请纠正我。)
所以安卓的人想,“嘿,那太低效了,让我们马上去一个基于寄存器的虚拟机......”?但是等等,有多个不同的 android 设备,Dalvik 的目标寄存器是多少? Dalvik 操作码是否针对一定数量的寄存器进行了硬编码?
市场上所有当前的 Android 设备是否具有大致相同数量的寄存器?或者,在 dex 加载期间是否执行了寄存器重新分配?这一切如何结合在一起?
基于堆栈的 VM 有一些属性非常适合 Java 的设计目标:
基于堆栈的设计对目标硬件(寄存器、CPU 功能)的假设很少,因此很容易在各种硬件上实现 VM。由于指令的操作数在很大程度上是隐式的,因此目标代码往往会更小。如果您要通过慢速网络链接下载代码,这一点很重要。
使用基于寄存器的方案可能意味着 Dalvik 的代码生成器不必费力地工作来生成高性能代码。在寄存器极其丰富或寄存器极少的架构上运行可能会妨碍 Dalvik,但这不是通常的目标——ARM 是一个非常中间的架构。
我也忘记了 Dalvik 的初始版本根本不包含 JIT。如果您要直接解释指令,那么基于寄存器的方案可能是解释性能的赢家。
我找不到参考资料,但我认为 Sun 决定采用基于堆栈的字节码方法,因为它可以很容易地在寄存器很少的架构上运行 JVM(例如 IA32)。
在 Google I/O 2008 的 Dalvik VM Internals 中,Dalvik 创建者 Dan Bornstein 在 presentation slides 的幻灯片 35 上提供了以下论据,用于选择基于寄存器的 VM:
注册机 为什么?避免指令分派 避免不必要的内存访问 有效地消耗指令流(每条指令的语义密度更高)
在幻灯片 36 上:
注册机 统计信息 指令减少 30% 代码单元减少 35% 指令流中的字节增加 35% 但我们一次可以消耗两个
根据 Bornstein 的说法,这是“将一组类文件转换为 dex 文件时可以找到的一般期望”。
presentation video starts at 25:00 的相关部分。
还有一篇题为 "Virtual Machine Showdown: Stack Versus Registers" by Shi et al. (2005) 的有见地的论文探讨了基于堆栈和基于寄存器的虚拟机之间的区别。
我不知道为什么 Sun 决定基于 JVM 堆栈。 Erlangs 虚拟机,BEAM 出于性能原因是基于寄存器的。由于性能原因,Dalvik 似乎也是基于寄存器的。
Dalvik 使用寄存器作为主要的数据存储单元,而不是堆栈。谷歌希望因此能减少 30% 的指令。
关于代码大小:
Dalvik VM 获取生成的 Java 类文件并将它们组合成一个或多个 Dalvik 可执行文件 (.dex) 文件。它重用了来自多个类文件的重复信息,有效地将空间需求(未压缩)比传统的 .jar 文件减少了一半。例如,Android 中 Web 浏览器应用的 .dex 文件约为 200k,而等效的未压缩 .jar 版本约为 500k。闹钟的 .dex 文件大小约为 50k,大约是 .jar 版本的两倍。
我记得 Computer Architecture: A Quantitative Approach 还得出结论,寄存器机器比基于堆栈的机器性能更好。
不定期副业成功案例分享