style - javadoc structure




Java真的很慢嗎? (13)

Java有一定程度的緩慢聲譽

  • Java真的很慢嗎?
  • 如果是,為什麼? 瓶頸在哪裡? 是否因為效率低下的JVM? 垃圾收集? 純字節碼庫而不是JNI包裝的C代碼? 許多其他語言都具有這些功能,但他們沒有這種緩慢的聲譽。

“漫長的啟動時間”中的罪魁禍首是動態鏈接。 Java應用程序由編譯的類組成。 每個類按名稱引用其他類(對於參數類型,方法調用...)。 JVM必須在啟動時檢查並匹配這些名稱。 它是逐步完成的,在任何時候只做它需要的部分,但這仍然是一些工作要做。

在C應用程序中,該鏈接階段發生在編譯結束時。 它很慢,特別是對於大型應用程序,但只有開發人員才能看到它。 鏈接產生一個可執行文件,操作系統只需按“原樣”加載到RAM中。

在Java中,每次運行應用程序時都會發生鏈接。 因此啟動時間很長。

已經應用了各種優化,包括緩存技術,並且計算機變得更快(並且它們比應用程序“變得更大”更快),所以問題重要性最近已經大大減少; 但舊的偏見依然存在。

至於後來的性能,我自己在基於數組訪問(通常是散列函數和其他加密算法)的緊湊計算上的基准通常表明優化的C代碼比Java代碼快大約3倍; 有時C比Java快30%,有時C可以快4倍,這取決於實現的算法。 由於處理器提供了64x64-> 128乘法操作碼,但“Java”不能使用,因為它的最長整數類型是64位long ,所以當“C”代碼實際組裝大整數運算時,我看到了10倍的因子。 這是一個邊緣案例。 在實際情況下,I / O和內存帶寬考慮因素會阻止C代碼比Java快三倍。


Java在一天之後很慢。 由於幾代性能的提升 ,它變得更快 。 最後我聽說,它通常在C#速度的10%以內 - 有時更快,有時更慢。

Java applet的啟動仍然很慢,因為你必須啟動一個完整的JVM,它必須加載所有的類。 有點像啟動另一台電腦。 一旦JVM啟動,它非常快,但啟動通常是人們記住的事情。

此外, 至少有一些人永遠不會相信Java的可行性。


Java是一種高級語言,其聲譽現在與其他可比較的高級語言相當。

  1. 它具有動態綁定語義。 與非虛擬方法編譯為函數調用的C ++相比,即使是世界上最好的Java編譯器也必須生成效率較低的代碼。 但它也是一種更清潔,更高級的語義。

  2. 我不記得細節,但是在Java的早期我聽說每個Java對像都有一個互斥體,可以通過每種方法獲取和發布。 這往往會使它更好地適應並發性,但不幸的是,只是每個對象的互斥體不能保護您免受種族,死鎖或任何可能發生在並發程序中的不良情況。 如果真的,那部分是有點天真,但它來自好意。 如果您對這方面有更多了解,請隨時填寫詳細信息。

  3. Java是高級語言的另一種方式是通過Garbage-Collection 。 垃圾收集可能比malloc慢,對於一次分配所有需要的內存並對其進行處理的程序而言,垃圾收集可以是free的。 問題是,在沒有Garbage-Collection的語言中,程序員傾向於寫程序來分配他們一次需要的所有內存,如果結果是一些任意的最大大小常量被溢出,則會失敗。 所以比較是橙子蘋果。 當程序員努力通過動態分配非GC語言的鍊式結構來編寫和調試程序時,他們有時會發現他們的程序不再比GC語言更快,因為mallocfree是不免費的! 他們也有開銷......另外,沒有GC力量來指定誰可以釋放什麼,並且必須指定誰釋放什麼,有時候會強制你複製 - 當幾個函數需要這些數據時,並且不清楚哪個將最後使用它 - 而在GC語言中不需要復制。


Java的速度很慢,因為速度慢。 Java的第一個版本沒有或者很差的即時編譯。 這意味著代碼儘管字節碼被解釋,所以即使對於最簡單的操作(如添加兩個整數),機器也必須進行各種比較以及指針解引用和函數調用。 JIT編譯器一直在不斷完善; 現在,如果我不小心編寫C ++代碼和不小心編寫Java代碼,Java有時會勝過 C ++,因為JIT編譯器意識到我已經得到了一些不必要的指針解引用,並且會為我處理它。

如果你想看看JIT編譯帶來的差異有多大,請查看計算機語言基準遊戲的解釋性與非解釋性基準。 (Pidigits使用一個外部庫來完成所有的計算,所以基準不會改變,其他的則顯示6-16倍的加速!)

所以,這是主要原因。 有許多其他原因並沒有幫助:最初,Java啟動時間很慢(現在已經修復); Java中的網絡應用需要很長時間才能下載(現在對於寬帶可用性來說現在更不容易了,而且預計電影等大型應用)。 UI Swing沒有(現在也沒有)寫出性能的標準,所以它比C ++中的等效性要少得多。


人們通常走出“解釋”的路線。 因為曾經一度,那些糟糕的新聞被那些甩掉Java的人“傳得太慢”並且從未返回來測試新版本的人傳下來。

或者“人是白痴”是一個更好的答案。


你似乎在問兩個相當不同的問題:

  1. Java真的很慢,為什麼?
  2. 為什麼Java被認為很慢,即使它比許多選擇更快?

其中第一個或多或少是“繩子多久”的問題。 這歸結於你的“慢”的定義。 與純粹的解釋器相比,Java非常快速。 與(通常)編譯成某種字節碼的其他語言相比,然後動態編譯為機器代碼(例如C#或.NET上的其他任何語言),Java大致相當。 與通常編譯為純機器代碼的語言相比,並且(通常是大型的)團隊只需改進其優化器(例如C,C ++,Fortran,Ada)就可以完成很多工作,但總體而言往往至少有點慢。

這很大程度上與實現有關 - 基本上,這歸結於用戶在動態/ JIT編譯器運行時等待的事實,因此除非您有一個運行相當長一段時間的程序,否則它是難以讓編譯器花費大量時間進行困難的優化。 因此,大多數Java(和C#等)編譯器都不會付出很多努力來進行真正困難的優化。 在很多情況下,它不是什麼優化完成,而是應用程序的位置。 很多優化問題都是NP完整的,所以它們所花費的時間會隨著問題的大小而迅速增長。 在合理範圍內保持時間的一種方法是,一次只將優化應用於某個功能。 當只有開發人員在等待編譯器時,您可以花費更多時間,並將相同的優化應用於程序的更大塊。 同樣,用於某些優化的代碼非常多(因此可能非常大)。 同樣,由於用戶在代碼加載的同時等待(並且JVM啟動時間通常是整個時間中的重要因素),因此實現必須平衡在一個地方保存的時間與在另一個地方丟失的時間 - 並且給定代碼從多毛優化中受益,使JVM保持較小通常更有利。

第二個問題是,對於Java,您經常會得到或多或少的“一刀切”的解決方案。 舉例來說,對於許多Java開發人員來說,Swing實質上是唯一可用的窗口庫。 在像C ++這樣的東西中,實際上有幾十個窗口庫,應用程序框架等,每一個都有其易用性與快速執行之間的一系列折衷,與本地外觀和感覺相一致的外觀和感覺等等。 唯一真正的問題是有些(如Qt)可能相當昂貴(至少用於商業用途)。

第三,用C ++編寫的代碼(甚至更多)更簡單,更老,更成熟。 在很多情況下,它包含幾十年前編寫的例程的核心,當花費額外的時間優化代碼是正常的,預期的行為。 這通常在代碼更小更快時帶來真正的好處。 C ++(或C)獲得了代碼小而快的功勞,但它實際上更多地是開發人員的產品和編寫代碼的時間限制。 在某種程度上,這導致了一種自我實現的預言 - 當人們關心速度時,他們經常選擇C ++,因為它具有這種聲譽。 他們花費額外的時間和精力進行優化,並編寫新一代快速C ++代碼。

總而言之,Java的正常實現最大限度地使最大化優化成為問題。 更糟的是,在Java 可見的地方 ,窗口工具包和JVM啟動時間等任何事情往往比語言本身的執行速度起到更大的作用。 在很多情況下,C和C ++也會因為優化而更加努力地工作而獲得功勞。

關於第二個問題,我認為這主要是工作中的人性問題。 一些狂熱分子對Java的炫耀速度相當誇張。 有人試用它,發現即使是一個微不足道的程序也需要幾秒鐘的時間才能開始,並且在運行時感覺緩慢而笨拙。 很少有人可能會費心去分析一些事情,認識到這其中有很多是JVM的啟動時間,以及當他們第一次嘗試時,沒有任何代碼已經被編譯 - 一些代碼正在被解釋,有些正在等待編譯。 更糟糕的是,即使運行速度足夠快,對於大多數用戶來說,外觀和感覺通常會顯得異常和笨拙,所以即使客觀測量顯示響應時間很快,它仍然顯得笨拙。

把它們加在一起會導致一個相當簡單和自然的反應:Java很慢,很醜,很笨拙。 鑑於大肆宣傳它速度很快,有一種反應過度的傾向,並認為它的速度非常緩慢,而不是(更準確),“稍微慢一點,而且大多是在特定情況下。” 對於編寫該語言的前幾個程序的開發人員來說,這通常是最糟糕的。 在大多數語言中執行“hello world”程序是即時的,但在Java中,JVM啟動時會有一個容易察覺的暫停。 即使是一個純粹的解釋器,在緊密的循環中運行速度要慢得多,對於這樣的代碼來說,這樣的代碼通常也會更快,因為它可以加載並且可以更快地開始執行。


在閱讀完整的評論說Java不慢,我只需要回答一個不同的意見。

語言的緩慢性很大程度上取決於你對“快速”的期望。 如果你認為C#很快,Java肯定也會很快。 如果您的問題域與數據庫或半實時處理相關,Java肯定也足夠快。 如果您很高興通過添加更多硬件來擴展您的應用程序,那麼Java對您而言可能會很快。 如果您認為5-10的恆定因子加速並不值得,那麼您可能會認為Java很快。

如果您在大型數據集上進行數值計算,或者綁定到CPU資源有限的執行環境,那麼規模為5-10的恆定加速將非常龐大。 即使0.5加速也可能意味著要完成500小時的計算。 在這些情況下,Java不允許你獲得最後一個性能,你可能會認為Java速度很慢。


它是Java早期(90年代中後期)的過時信息。 與以前的版本相比,Java的每個主要版本都引入了顯著的加速。 隨著Oracle顯然將JRockit與Sun的JVM for Java 7合併,這一趨勢似乎將持續下去。

與許多其他流行的現代語言(Python,Ruby,PHP)相比,Java在大多數用途上實際上顯著更快。 它不完全符合C或C ++,但對於許多任務來說它足夠接近。 真正的性能問題應該是關於它最終使用多少內存。


我認為有一天,也許不是在不久的將來,由於JIT編譯器可以大量使用運行時間,所以JIT編譯語言在任何方面都會超過編譯語言(可能不是啟動時間/內存消耗) behaviour and the platform they're running on.


推出麵團的錘子比其他許多工具慢得多。 不要讓錘子“變慢”,對於它所設計的任務來說也不那麼有用。

作為一種通用的編程語言,Java與許多編程任務(如果不是最多的話)相當。 有一些特殊的,簡單的測試,對於Java來說,在不太複雜的語言中,手寫代碼解決方案的性能不會超越手工編碼的解決方案,而是“更接近金屬”的。

但是當涉及到“真實世界的應用程序”時,Java通常是正確的工具。 現在,這就是說,沒有什麼會阻止開發人員使用ANY工具製作性能較低的解決方案。 濫用工具是一個眾所周知的問題(只要看看PHP和VB的聲譽)。 但是,Java(大部分)乾淨的設計和語法確實可以減少濫用。


最初Java並不是特別快,但也不是太慢。 現在,Java非常快。 從我談到的人們對Java緩慢的印象來看,有兩件事:

  1. 虛擬機啟動時間慢。 與本機應用程序相比,早期的Java實現需要很長時間才能啟動並加載require庫和應用程序。

  2. 慢UI。 早期的Swing很慢。 它可能沒有幫助,大多數Windows用戶發現默認的金屬L&F醜陋。

鑑於以上幾點,難怪人們得到了'Java慢'的印象。

對於用於開發本機應用程序甚至是Visual Basic應用程序的用戶或開發人員來說,這兩點是應用程序中最明顯的一點,這是您對應用程序的第一印象(除非它是一個非GUI應用程序情況只適用於1.)。

即使代碼執行和啟動時間可能根本不連接,您也不會說服用戶“應用程序執行代碼非常快”,而應用程序需要8秒才能啟動,而不是立即啟動舊的Visual Basic應用程序。

破壞第一印像是啟動謠言和神話的好方法。 謠言和神話很難殺死。

總之,Java並不慢。 擁有“Java是緩慢的態度”的人基於10多年前對Java的第一印象。


正如帕斯卡爾所說,Java與其他高級語言一樣。 但是,作為在Windows 98上使用原始JVM的人員,在Java虛擬機提供抽象級別時,我們應該說是痛苦的。

基本上,這是在沒有優化的情況下進行的軟件仿真,我們今天在JVM中認為是理所當然的。


許多Java桌面應用程序(這些時間:諸如Eclipse之類的東西)具有不良的GUI響應能力,這可能是由於高內存消耗和類加載器可以執行大量IO的事實。 它正在改善,但幾年前更糟。

許多(大多數)人喜歡進行概括,所以他們說“Java很慢”,因為他們認為應用程序在與它們交互時很慢。





performance