想起来之前看到郭神下面一个留言比较有意思,说网上很多文章说dalvik虚拟机是基于寄存器的,而jvm是基于栈的,由此引发的讨论,可以看图。
疑问1,在基于寄存器的架构下,方法运行就不会产生栈帧吗?
疑问2,如果疑问1是否定的,那么基于寄存器这个概念到底说的是什么?
更多问答 >>
-
2020-05-25 23:08
-
每日一问 在 Java 支持了 switch(字符串)之后,只是语法糖而已?
2020-06-01 00:55 -
2020-06-07 20:55
-
每日一问 | Activity与Fragment的那些事,“用起来没问题,我都要走了,你崩溃了?”
2020-06-22 00:39 -
2020-06-09 23:17
-
2020-05-21 01:15
-
每日一问 | Activity 调用了finish()方法会立即调用onDestory()吗?
2020-05-13 00:16 -
2020-05-07 10:02
-
每日一问 “PathClassLoader 只能加载已安裝到系統中(即/data/app目录下)的apk文件” 严谨吗?
2020-05-05 20:46 -
每日一问 | “必须在UI线程才能更新控件/界面” 这句人人皆知的话,100%正确吗?
2020-04-29 01:14
说一下我自己的理解吧:
首先放个传送门:栈式虚拟机和寄存器式虚拟机的区别?,R大已经做过比较详细的解答了问题一:在基于寄存器的架构下,方法运行就不会产生栈帧吗?
显然会,不过栈是虚拟机内部实现的一部分,不会直接暴露出来(给指令操作栈)。最简单的问题就是,在smali里,“寄存器”是每个方法隔离的,你在这个方法操作某个寄存器,在方法外是感知不到的,不用自己保存寄存器;这是怎么做到的呢?
这个“寄存器”并不是cpu里那个寄存器,别搞混了,虚拟机内部可以把它映射到真实的物理寄存器,也可以映射到栈里;如果映射到真实寄存器的话,为了不破坏之前的值,就要对它进行保存,保存到哪里呢?答:还是栈里。我们可以写代码验证一下有栈:java字节码:
ldc就是压栈,把参数:2001361295压到栈里。
编译成smali是这样的:v0就是“寄存器”。
发现了什么没有?java字节码里的invokestatic不直接接收参数,而是用栈来传递;而smali里的invoke-static指令是要求带上参数的。ok,继续;我们把dex编译成oat,然后可以使用oatdump把里面的代码反汇编出来(注:我这用的是x86指令集,arm指令集类似):这段代码里你可以很清晰的看见push和pop指令,还有对esp(栈指针)的操作;另外,x86下call还会把下一条指令的地址存到栈里,方便target函数执行完成后返回。
(注:这里做了简化,只是为了表明栈存在,实际上看寄存器保存什么的应该写smali实现那个target然后看target)你看,处处都是栈!另外推荐一篇讲x86下函数调用文章:CPU阿甘:函数调用的秘密,你能理解到cpu和内存是怎么配套工作的,栈到底是什么等等。注:这里主要讨论ART,实际上虚拟机栈和native栈略有不同,虚拟机栈可以由虚拟机自己实现,不过由于hotspot/art中都把两个栈实现在一起,所以我直接讲native栈了问题二:那么基于寄存器这个概念到底说的是什么?
答:基于栈的虚拟机支持顺序访问,基于寄存器的虚拟机支持随机访问;最直观的表现就是,在java字节码里,调用一个函数时实际的invokexxx指令只要求指定被调用方法,参数必须通过栈来传递;而基于寄存器的smali里,invoke-xxx指令要求你带上参数,以寄存器的方式传递。
然后是效率问题,在只考虑解释器的情况下,基于寄存器的虚拟机内存访问次数会较少;编译成机器码之后,基本上就不用考虑字节码是用寄存器还是栈了,效率就差不多了,编译器会根据目标设备的指令集架构自己处理好。非常赞
学习了
膜拜大佬