1. 程式人生 > >Java VS C/C++ 執行速度的對比

Java VS C/C++ 執行速度的對比

http://blog.sina.com.cn/s/blog_99baab530102wj4e.html

Java與C++相比的優點在於:

u  Java比C,C++簡單,學起來比C\C++容易

u  Java完全物件化,比如陣列在Java中是一個物件,含有length這個屬性;而不像C++中陣列是一個指標。所以訪問陣列,Java都會進行邊界檢查,更安全,但犧牲了速度。同時因為Java中所有類都會繼承Object基類,所以可以把幾個好不相干的類用基類聯絡起來,比如放在同一個數組裡。

u  Java中沒有指標的概念。

u  Java中有完善的記憶體管理機制,能自動垃圾回收,最大可能降低記憶體溢位的可能,同時提高程式設計效率。

u  Java中有完善的異常機制(標準C++中不夠完善)。

u  java中保持資料時物件本身是在堆裡,同時靠一在棧裡的控制代碼與之連線。這個設計更合理。

u  Java標準庫完整的多,相比之下C++除了一個STL(而且還超級難用)就沒了,實際C++程式設計中需要大量使用第3方庫。這很大程度上是因為Java有一些商業公司支援,更新速度快,而C++只有一個可憐的標準委員會,上一個C++標準版本還是C++98。

u  Java因為是把程式編譯為位元組碼,執行時需要JVM把位元組碼再翻譯為機器碼,所以他跨平臺,一次編譯到處執行。但這也是他慢的根本原因。

u  Java原生支援多執行緒(C++僅靠標準庫辦不到),原生的UI,如AWT Swing。

C++與Java相比的優點在於:

l  Java比C\C++慢。Java 1.0 比C慢20倍 現在的Java 1.6執行速度也只是C的一半。

l  C++在繼承和派生上比Java更靈活。

l   C++ 中可以直接插入彙編 能直接操控底層硬體 所以作業系統還是得用c寫。

l  Java辦的到C++一定辦得到,C++辦得到的Java則不一定。

l  Sun被甲骨文收購了之後,Java的發展很受影響。

l  C++編譯的程式可以直接執行,Java需要安裝JRE有幾十MB,影響產品釋出的使用者體驗。

1.2 常規思維:C/C++Java

常規認為:java執行速度比C++慢。主要原因是:

l  java是解釋性語言,java程式在執行時類載入器從類路經中載入相關的類,然後java虛擬機器讀取該類檔案的位元組,執行相應操作。而C++編譯的時候將程式編譯成本地機器碼。一般來說java程式執行速度要比C++慢10-30倍。即使採用just-in-time compiling (讀取類檔案位元組後,編譯成本地機器碼)技術,速度也要比C++慢好多。

l  java程式有要從網路上載入類位元組,然後執行,這也是導致java執行速度慢的原因。

l  在程式執行過程中,java虛擬機器要檢測陣列是否越界,在C++中則不檢測。

l  java中所有的物件都建立在堆中,沒有物件被建立在stack中,而C++有的物件和變數是建立在stack中的

l  java在執行過程中檢測物件的引用是否為空,如果引用指向都空指標,且執行某個方法時會丟擲空指標異常

l  java執行時對型別檢測,如果型別不正確會丟擲ClassCastException異常。

l  java的垃圾回收機制較C++由程式設計師管理記憶體效率更低。

l  java中的原始資料型別在每個作業系統平臺長度都是相同,而C++這些資料型別長度是隨作業系統的不同而不同,所以java在不同作業系統上執行時有個轉化過程。

l  在java中String 是UNICODE.當java要操作一個 ASCII string 時,比C++效率上相對要低一些。

l  java中採用的是動態連結。

可以看出,這些比較,全部停留在理論的角度。那麼實際應用如何呢?是騾子是馬,需要拉出來溜溜嘛!

1.3 實際權威測試結果

http://nuclearjava.blogchina.com/642833.html

Java比C++快的理論依據

http://nuclearjava.blogchina.com/1792677.html

駁“.net比java快”的謊言

http://nuclearjava.blogchina.com/1902610.html

摘要

C++的速度是由C++編譯器在程式設計師開發時編譯出來的機器語言的優化程度決定的。

Java的速度是由Java的JIT和HotSpot編譯器將java bytecode在執行時“即時”編譯成針對本地CPU的優化的原生代碼決定的。

比速度的實際就是在比:看C++編譯器和java編譯器誰能產生更優化的機器程式碼。

很明顯,C++的編譯器不如java的JIT和HotSpot編譯器,因為JIT和HotSpot編譯器能針對CPU指令集進行人優化、能在執行時根據使用頻率對method進行內聯和優化。而C++的靜態編譯器永遠也做不到這些。

據IBM研究院的資料顯示,隨著java技術的進步,java在同樣的硬體上的效能從1996年到2001年提高了10倍,而且還在不斷提高。

SUN的資料顯示:j2se 1.5在各種單項效能上平均比j2se 1.4.2高出10%到30%,而在複雜程式的綜合性能上則是j2se1.4的三倍左右。

在丹麥Copenhagen大學的一份長達314頁的研究報告中,我們看到:

JDK 1.0時,java的速度是C++的20到40分之一。而到了jdk1.4時,java的效能則是C++的三分之一到2倍(通常C++是java的1.2倍到1.5倍)。在jdk 1.4.2時,java效能全面超過C++。

java在j2se 1.4.2時就已經在效能上全面超過了以c++,以下是幾十個權威證據。

美國國家標準科技研究院 12項測試中,java獲勝7項,C獲勝5項。結論:大多數情況下,java更快;

蘋果電腦公司的一份報告:在字串比較上,Java的效能是C的6.4倍:

美國國家標準科技研究院的另一份報告證明:Java的全面戰勝同時代的VC和Borland C;

Java寫的資料庫的效能是C++寫的資料庫效能的近600倍!

BGS Systems 公司的三位作者的共同研究報告:我們開始測試是否java程式能夠接近C++的效能。但我們吃驚的發現:在client/server應用程式中,java效能優於MFC。

伯克利大學和Lawrence伯克利國家實驗室的一份報告證明:IBM的JDK比GCC更快:

用純java寫的JDK底層要比用C++寫JDK底層要快:

JNode是一個純java的作業系統,其jdk底層是用純java寫的。

美國國家標準研究院的一分報告:Java戰勝MS VC++ Netbot 聯合公司的證據:http://www.javaworld.com/javaworld/jw-02-1998/jw-02-jperf_p.html

中: java和C++在以下方面打成平手

Integer division

Dead code

Dead code with Integer division

Floating-point division

Static method

Member method

Virtual member method

但java在以下方面的速度是C++的約3倍

Virtual member method with down cast and Run-Time Type Identification (RTTI)

http://www.kano.net/javabench/data

14項Benchmark中,Java獲勝9項,C++5項 。java以9:5戰勝C++,而且其中很多項是以大比分領先:

Methord Call:近20倍

Object creation:4倍

Hash: 2倍半

word count:1倍半

Fibonacci:1倍半

http://cpp.student.utwente.nl/benchmark/

結果:

14個Benchmark中

Java-server SUN JDK1.4.2以6比8負於Inter C++8.0

Java-server SUN JDK1.4.2以8比6戰勝GCC-i686

Java-server SUN JDK1.4.2以7比7戰平GCC-i386

結論:基本戰平

但是在此測試中,作者說他“故意”限制了JVM的記憶體使用量,說這是為了和C++公平。這其實是很不公平的。

java開啟-server的目的就是為了“用空間換時間”,在記憶體中將bytecode編譯成更大但是更快的本地碼,作者卻限制記憶體使用,

就如同飛機與汽車比速度時給飛機和汽車同樣數量的汽油一樣,或者在限制飛機的飛行高度為5米以下一樣(飛機在燃料不足或低空的情況下是不可能以最快的速度飛行了)

看似公平,實則極不公平,飛機就是靠大量的燃料來加速,不給燃料還比什麼呢?如果給飛機和汽車同樣多的燃料,飛機每跑100米就要停下來加一次油,怎麼可能發揮最快速度呢?

而且,所有的java程式都會比相同演算法的c++程式的記憶體用的多,畢竟JVM就要佔去很多記憶體,如果想比較java和c++的速度,就絕不能要求他們的記憶體是相同的,就如同想比較飛機和汽車誰快,就絕不能要求他們用的油是相同的。

如果不限制記憶體使用量的話,相信java會更快。

IBM研究的JVM已經證明了Java即使在數學運算中效能也超過C和Fortran。

Fortran90:Java的結果(單位為秒)

20:14

40:30

440:444

1080:1089

11790:11690

輸了的兩項是以不到1%的差距輸的

而贏了的三項中有兩項是以33%以上的差距獲勝的

而Java高效能編譯器只以2:3的微小差距略負於高效能Fortran(High-Performance Fortran, version 2.2.)

IBM的報告:Servlet與CGI的效能對比: 結論:Servlet效能大大超過用C寫的CGI:評測報告:.NET的效能仍然遠遠落後於Java

麻省理工大學的一位研究員的報告:再來看看用純java寫的MD5演算法FastMD5,使用JIT進行native編譯後的FastMD5,在linux上處理679,477,248 bytes 大的檔案,Java Fast MD5的成績是34.325秒,而用C寫的RedHat linux的textutils-2.0.14-2.i386.rpm用時是59.87667秒。而且,java經過一些設定後,速度還能比前面的更快。英文原文見:http://www.twmacinta.com/myjava/fast_md5.php

Swing GUI圖形介面的效能: 在選單、樹形、文字框、table等幾項上,jdk1.4.0比jdk1.3.1快40%到90%。Reflection的效能上,jdk1.4.0比jdk1.3.1快20倍!快20倍以上的還包括遠端視窗呼叫 。其它各項上,jdk1.4.0幾乎都比jdk1.3.1快50%以上,“Java慢”也只是“歷史”了 。其它各方面的效能提升在此

http://java.sun.com/j2se/1.4/performance.guide.html

SUN的資料說明,JDK1.4.2在各方面的效能是jdk1.4.1的50%到380% 可以看到,幾乎每次java的版本提高都帶來效能的極大提升。所以如果你在某處看到一個benchmark說C++比java快,那就很可能是用的老版本的java。 但是C++近年似乎沒什麼速度的提升

http://java.sun.com/j2se/1.4.2/1.4.2_whitepaper.html

英國愛丁堡平行計算中心(http://www.ukhec.ac.uk/publications/reports/hpc_java_comp.pdf),由於使用了古老的JDK1.3.1,而且沒有開啟-server選項執行java,所以不能代表java最高速度。儘管如此,還是能夠看到Java的效能非常接近C和Fortran:

在1000000次方法呼叫(method call)的測試中,Java 1.0的效能竟是C++的171.2%!也就是說:Java在1.0版本時就在"方法呼叫"這一項上超過了C++!

Dieselpoint公司:JDK 1.3就已能在某些方面超過同時代的VC 6.0 與Borland C:事實上,說“更快的程式http://dieselpoint.com/pdf/WhitePaper-JavaAndPerformance.pdf

JIT編譯器知道什麼處理器正在執行,可以產生對應此處理器的優化程式碼。它知道是否處理器是P3或P4,是否SSE2存在,cache有多大。一個C++之類的預先編譯器只能針對所有處理器的指令集的“最小公分母”進行編譯,至少在商業軟體中是這樣的。因為JIT編譯器知道哪些類被實際裝載和呼叫,它知道哪些方法可以被“消虛擬化(de-virtualized)” 和內聯(值得一提的是:當代。

Java code比C++更快的原因:C++進行的優化是靜態優化,都是在編譯的時候進行的。一旦編譯連結生成的可執行原生代碼,就蓋棺定論了, 不能更改了,除非是Hacker或是病毒。就現在的編譯技術來看,靜態優化在總體上還是最成熟的,並且在編譯的時候它沒有時間壓力,可以花很長時間來優化程式。這點Java和.NET是不允許的。但是靜態優化也有它的缺點,因為它不知道這些程式在執行的時候具體會有什麼特徵,無法針對性地進行優化。比如它就不可能“大膽”的進行Method inlining。因為它膽子大了就可能犯錯誤。比如一個Class A,它有個簡單函式public int Foo() {return 3;},它的兩個子類B和C Override了這個Foo()函式。那麼在靜態編譯的時候,C++的編譯器不能將Foo()這個函式作inlining優化,因為它不知道在執行的時候到底是A,還是B或是C的Foo()被呼叫。而在反覆被呼叫,那麼它就 大膽的將B的Foo()拿到呼叫者的程式裡面來,這樣的inlining處理避免了Function call的開銷(仔細說就是No method call;No dynamic dispatch;Possible to constant-fold the value)。對於簡單的小函式,呼叫開銷往往比執行還費時間。省略了這些開銷效能會成倍的提高。如果這些小函式被上千上萬次的呼叫,那麼這樣優化下來的效果就非常明顯了。這也就是Java在有的時候比C++更快的原因之一。當然,Java做優化實際上相當複雜,因為“大膽”優化有時候也會出現問題。比如 將B的Foo()的inlining了,結果突然的蹦出一個對A的Foo()的呼叫,那程式豈不是要出問題?這個時候呢,Java要退一步,進行反優化 (De-optimization),以確保程式的正確。就這樣,Java的虛擬機器“騎著毛驢看賬本---走著瞧”。一邊執行,一邊優化,執行不停,優化不止。從外表上看,Java的程式執行會不停的有小的波 動。我說的動態優化/反優化就是原因之一(還有很多其他原因)。Java這種特性非常適合長時間執行的伺服器端程式,因為這樣Hotspot才有足夠的機會對程式進行優化。如果程式只是簡單的“Hello world”,那Hotspot一點忙幫不上。並且對於“Hello world”這麼個簡單的程式,一個Java VM也要啟動,這就像你點著了一臺鍋爐,只是想煎一個雞蛋。好多人覺得Java慢,最初的影像可能就是來源於此。

有人這時候一定會問:“既然這樣,那為什麼Hotspot不對程式就行全盤優化,那樣豈不是更好?”。問題是這樣的,優化是有代價的。比如一段程式執行要 2毫秒,優化要10毫秒。如果這段程式的執行密度很低,那麼Hotspot就會覺得優化不划算而不予優化。你不妨這樣想,Hotspot是一個精明的商人,賠本的生意它絕對不會做。

最後再指出一點,那就是Hotspot有客戶機和伺服器兩套(-client, -server),它們有不同的優化方針和策略。

來源:http://aoyouzi.iteye.com/blog/1847682