1 回答

TA貢獻1854條經驗 獲得超8個贊
Java 和 Golang 程序在執行之前都被編譯成機器語言——這就是 JIT 代表 Java VM 的意思。至于性能比較,每個生成的機器碼之間肯定有不那么細微的差異。
不幸的是,我無法訪問 Java JIT 編譯器生成的機器碼,但我們可以看一下 Go 編譯器(v1.11.4-amd64)為函數生成的內容fibonacci:
# Do the comparison
MOVQ "c", AX
CMPQ AX, $2
JGE @ELSE
# Save the func result
MOVQ AX, "r"
# Clean up and return
MOVQ 24(SP), BP
ADDQ $32, SP
RET
@ELSE:
# Compute fib(c - 2)
LEAQ -2(AX), CX
MOVQ CX, (SP)
CALL fibonacci
# Save the call result
MOVQ 8(SP), AX
MOVQ AX, "temp"
# Compute fib(c - 1)
MOVQ "c", CX
DECQ CX
MOVQ CX, (SP)
CALL fibonacci
# Add previous results together
MOVQ 16(SP), AX
ADDQ 8(SP), AX
# Save the func result
MOVQ AX, "r"
# Clean up and return
MOVQ 24(SP), BP
ADDQ $32, SP
RET
請注意,這段代碼不是完全相同的輸出,但我對其進行了一些修改以使其更加清晰。引用的變量是堆棧位置。
我的結論是,雖然 Go 編譯器確實采用了一些優化技術來生成更高性能的代碼(請參閱編譯器優化),但它在分配 CPU 寄存器方面做得不是很好(與 C 編譯器生成的相比),并且依賴于堆棧太多,尤其是對于返回值——我認為必須有一個可能與語言工作方式相關的原因(例如多個返回值)。
更新 1
只是為了比較,這是 GCC (amd64) 為相同功能生成的機器碼:
pushq %rbp
movq %rsp, %rbp
pushq %r14
pushq %rbx
# Do the comparison
movq %rdi, %rbx
cmpq $2, %rbx
jge @ELSE
# Save "c" in "r"
movq %rbx, %rax
jmp @RETURN
@ELSE:
# Compute fib(i - 2)
leaq -2(%rbx), %rdi
callq fibonacci
# Compute fib(i - 1)
movq %rax, %r14
decq %rbx
movq %rbx, %rdi
callq fibonacci
# Add previous results together
addq %r14, %rax
@RETURN:
popq %rbx
popq %r14
popq %rbp
retq
更新 2
話雖如此,我堅信在實際項目中,語言運行時(例如對象分配、垃圾收集、調用間接、動態加載、并發支持等)會對程序的整體性能產生更大的影響,而不是功能級別的微優化。
- 1 回答
- 0 關注
- 178 瀏覽
添加回答
舉報