JVM的JIT優化所帶來的性能提升與C++之類比較那個好?
有人說Java的性能和c++差不多,因為Java有jit,動態分析優化比c++的靜態優化有優勢。
請問JIT動態優化所帶來的性能提升能夠彌補Java本身的性能不足嗎?
關注了一段時間@RednaxelaFX,正好最近在寫C++內存相關演算法,在這裡根據R大的回答整理一個易懂的回答吧!
相信題主並不是非常了解JVM的實現機制(我也不是非常了解),因此,對題主的問題,short answer:在某些特定的場合,JIT產生的彙編碼,和用C++寫一個相同功能的函數所產生的彙編碼,二者可以十分接近。
long answer:即使是使用JIT,並且,運行後一段時間達到一個穩定的狀態(JIT下Java的性能是緩慢上升的),Java仍有幾個繞不過去的坎,使得Java的速度無法超過[不計時間成本]編寫出來的C++程序。
1.Java的GC普遍使用check point,一個比較複雜的循環的末尾一定會有一個check point,相當於每次循環都要多做一個if判斷。JIT可能可以通過profile來減少check point,但如果循環內要進行線程同步,循環末尾的check point就是無法避免的。這一項,JIT略微加分。
2.多線程程序中,Java承諾嚴格保證指令執行順序,而C++則不承諾,但提供了五種內存序及atomic類,這使得Java程序要頻繁地發射內存屏障來保證指令順序,並且從原理上無法避免,但C++就有充分的自主選擇權。意思是,Java一攬子把事情全包了,但C++有權利選擇哪些要哪些不要。JIT不像靜態編譯那樣有足夠的時間分析哪些內存屏障是不必須的,但其實靜態編譯也不太可能分析出哪些內存屏障是可以去掉。這一項,JIT沒太大影響。
3.Java嚴格保證表達式內的求值順序,而C++一定程度上不保證(需要部分地人為指定)。例如,函數傳參時,C++不規定參數的求值順序,只規定入棧順序,但Java就規定了。做加法時,例如a是一個多線程共享變數,執行a+=b+=c+=d,如果abcd都是unsigned,C++可以接受a=(a+b)+(c+d)這樣的求值順序(因為沒有發射內存屏障,編譯器可以考慮這樣的優化),a的值是從a「突變」到a+b+c+d的,但Java就不可以接受,a一定是從a變到a+b再變到a+b+c再變到a+b+c+d的。JIT不像靜態編譯那樣有充足的時間來分析,看錶達式是否接受「亂序」。多次執行同一代碼塊後,JIT可能會進行優化。這一項,JIT減分。
4.運行時類型識別。每生產一個類,Java就要做一些額外的工作來保證類型識別,即使只是在類的開頭增加一個type id。對於一些非常小的類,靜態編譯可以有足夠的時間把這個類放在棧上,優化這個類。JIT的行為要看具體實現。這一項,JIT不加分不減分。
可以看出,對於Java這門語言的「硬傷」,JIT是無法優化的。所以理論上Java不可能比C++快,當然前提是你有無限的時間來寫C++代碼。
動態優化只能說和靜態優化各有千秋。對於比較容易的優化,動態優化更容易利用第一手的信息;相對的靜態優化可以進行更複雜的處理。
Java的很多坑不是靠JIT救得了的。Java比OC快姑且還有可能,比C++快那是做夢。特定環境下的特定處理Java跑出比C++高的速度說明不了問題。Java充其量只能說在絕大多數情況下沒慢到不能容忍,不得不去犧牲開發成本的程度。不是哪個好的問題。有幾個要區分的問題:
1) JVM中 JIT不是萬能的,
2) JIT是有開銷代價的(包括Profiling和startup等等)。
3) 要是你沒有多平台的限制,以及知道哪些代碼優化等等,C++ 更好。
java與c++相比,最大的性能上的缺陷就是GC的問題。c++/c等使用靜態編譯之後,可直接運行在OS之上的語言,對於coder在內存分配和釋放的要求是相當嚴格的。 而java將內存的回收,交給了jvm,雖然實現了一些Nb的演算法(諸如:可達性分析,分代回收,複製演算法,標記清除,標記整理)來自動回收。但是再智能的演算法,也不可能由人為來操作內存來得直接,準確。JIT等及時編譯技術的加入,使得JVM可以利用運行中數據,綜合考慮分析,得到最優的動態編譯結果,確實使得java的性能得到一定的提升。但是比起c++還是有難以逾越的坎。最後說一下,c++比起java更靠近硬體,與硬體聯繫更密切,性能肯定是更高的,象彙編肯定比c/c++還要好
不要把兩者對立起來撒~
看bing搜索引擎(排行第一答案里說的有無限時間的主顧)的選擇,用C++,然後再給C++寫個JIT。
BitFunnel/NativeJIT
推薦閱讀:
※想做軟體開發,學哪種語言比較好?
※聽說過面向工資編程嗎?面向工資編程是怎樣一種體驗?
※需要前後端通吃嗎?
※PHP是最棒的語言,這個梗 從何而來?