C/C++爲什麼比JAVA快

大多數程序員都認爲C/C++會比Java語言快,甚至於覺得從Java語言誕生以來,“執行速度緩慢”的帽子就應當被扣在頭頂,這種觀點的出現是由於Java剛出現的時候JIT編譯技術還不成熟,主要靠解釋器執行的Java語言確實性能比較低下。但是在今天JIT編譯技術已經發展成熟之後,Java語言有可能在速度上與C/C++爭一日長短了嗎?這個問題的答案,讓我們從兩者的編譯器談起。

  Java與C/C++的編譯器對比實際上是代表了最經典的JIT編譯器與靜態編譯器的對比,也很大程度上決定了Java與C/C++的性能對比的結果,因爲無論是C/C++還是Java代碼,最終編譯之後被機器執行的都是本地機器碼,哪種語言性能更高,除了它們自身的API庫實現得好壞以外,其餘的比較就成了一場“拼編譯器”、“拼輸出代碼質量”的遊戲。當然,這種比較也是剔除了開發效率的片面對比,語言間孰優孰劣,誰快誰慢的問題都是很難有結果的爭論,下面我們就回到正題,看看這兩種語言的編譯器各有何優勢。

  Java虛擬機的JIT編譯器與C/C++的靜態優化編譯器相比,可能會由於下列這些原因導致輸出的本地代碼有一些劣勢(下面列舉的也包括一些虛擬機執行子系統的性能劣勢):

  首先,因爲JIT編譯器運行佔用的是用戶程序運行時間,具有很大的時間壓力,它能提供的優化手段也嚴重受制於編譯成本。如果編譯速度不能達到要求,那用戶將在啓動程序或程序的某部分察覺到重大延遲,這點使得JIT編譯器不敢隨便引入大規模的優化技術,而編譯的時間成本在靜態優化編譯器中並不是主要的關注點。

  其次,Java語言是動態的類型安全語言,這意味着需要由虛擬機來確保程序不會違反語言語義或訪問非結構化內存。在實現層面上看,這就意味着虛擬機必須頻繁進行動態檢查,如對象實例訪問時檢查空指針、數組元素訪問時檢查上下界範圍、類型轉換時檢查繼承關係等等。對於這類程序代碼沒有明確寫出的檢查行爲,儘管編譯器會努力進行優化,但是總體上仍然要消耗着不少的運行時間。

  Java語言中雖然沒有virutal關鍵字,但是使用虛方法的頻率卻遠遠大於C/C++語言,這意味着運行時對方法接收者進行多態選擇的頻率要遠遠大於C/C++語言,也意味着JIT編譯器在進行一些優化,如方法內聯時難度要遠大於C/C++的靜態優化編譯器。

  Java語言是可以動態擴展的語言,運行時加載新的類可能改變程序類型繼承關係,這使得很多全局的優化都難以進行,因爲編譯器無法看見程序的全貌,許多全局優化措施都只能以激進優化的方式來完成,編譯器不得不時刻注意並隨着類型變化而在運行是撤消或重新進行一些優化。

  Java語言中的對象內存分配都是堆上進行,只有方法中的局部變量纔在棧上分配。而C/C++的對象則有多種內存分配方式,既可能在堆上分配,也可能在棧上分配,如果可以把線程私有的對象在棧上分配,將可以減輕內存回收的壓力,也不需要考慮內存屏障方面的問題。另外,C/C++中主要由用戶程序代碼來回收分配的內存,這就不存在無用對象篩選的過程,因此效率上(僅指運行效率,排除了開發效率)也垃圾收集機制要高。

  Java語言相對C/C++的劣勢上面說了一大堆,倒不是說Java就真的不如C/C++了,相信大家也注意到了,Java語言的這些性能上的劣勢都是爲了換取開發效率上的優勢而付出的代價,動態安全、動態擴展、垃圾回收這些“拖後腿”特性都爲Java語言的開發效率作出了很大貢獻。何況,也不見得就沒有Java的JIT編譯器能做,而C/C++的靜態優化編譯器不能做的優化:由於C/C++編譯器的靜態性,以運行期性能監控爲基礎的優化措施它都無法進行,如調用頻率預測(Call Frequency Prediction)、分支頻率預測(Branch Frequency Prediction)、裁剪未被選擇的分支(Untaken Branch Pruning)等,這些都會形成一些Java語言獨有的性能優勢。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章