style Java真的很慢嗎?




javadoc structure (16)

Java肯定很慢,特別是對於量化工作。

我將R ,Python和C / C ++與優化的多線程ATLAS庫結合使用。 在這些語言中的每一種中,我都可以矩陣在大約4秒內乘以一個3000乘3000的雙精度矩陣。 在Java中使用Colt和Parallel Colt,同樣的操作需要185秒! 令人驚訝的是,儘管這些Java庫本質上是並行的。

總而言之,純Java不適合定量工作。 Jblas似乎是使用ATLAS的Java中最好的線性代數庫。

我的機器是帶有3 GB RAM的HP Core 2 Duo 。 我使用64位Ubuntu 10.04 (Lucid Lynx)。

Java有一定程度的緩慢聲譽

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

現代Java是最快的語言之一,即使它仍然是一個內存豬。 Java因速度慢而聲名狼借,因為它過去需要很長時間才能啟動虛擬機。

如果您仍然認為Java很慢 ,請參閱基準遊戲結果。 以提前編譯語言(C,Fortran等)編寫的緊密優化代碼可以勝過它; 然而,Java的速度可能比PHP,Ruby,Python等快10倍以上。有一些特定領域可以擊敗公共編譯語言(如果他們使用標準庫)。

現在沒有理由“慢”Java應用程序。 開發人員和遺留代碼/庫的責任,遠遠超過語言。 另外,責怪任何'企業'。

公平對待“Java是緩慢的”人群,這裡仍然是緩慢的領域(2013年更新):

  • 圖書館通常是為了“正確性”和可讀性而編寫的,而不是性能。 在我看來,這是Java仍然存在不良聲譽的主要原因,特別是服務器端。 這使得字符串問題呈指數級惡化。 一些簡單的錯誤很常見:對象通常用於代替原語,降低性能並增加內存使用量。 許多Java庫(包括標準庫)會頻繁創建Strings,而不是重複使用可變或更簡單的格式(char []或StringBuffer)。 這很慢,並創建大量的垃圾,以便以後收集。 為了解決這個問題,我建議開發人員盡可能使用原始集合,特別是Javalution的庫。

  • 字符串操作有點慢。 Java使用不可變的, UTF-16編碼的字符串對象。 這意味著你需要更多的內存,更多的內存訪問,並且一些操作比ASCII(C,C ++)更複雜。 當時,這對於可移植性來說是正確的決定,但性能成本很低。 UTF-8現在看起來更好。

  • 由於邊界檢查,數組訪問比C慢一些 。 懲罰過去很大,但現在很小(Java 7優化了大量冗餘邊界檢查)。

  • 缺乏任意的內存訪問可能會使某些I / O和位級處理變慢(例如,壓縮/解壓縮)。 這是現在大多數高級語言的安全功能。

  • Java使用的內存比C多得多,如果你的應用程序是內存綁定或內存帶寬綁定(高速緩存等),這使得它更慢。 另一方面是分配/釋放快速(高度優化)。 這是現在大多數高級語言的一個特性,由於對象和GC使用而不是顯式的內存分配。 再加上圖書館的不好決

  • 基於流的I / O速度很慢,因為(IMO,糟糕的選擇)需要在每個流訪問上進行同步。 NIO解決了這個問題,但使用起來很NIO 。 我們可以通過讀取/寫入數組而不是一次一個元素來解決這個問題。

  • Java不提供與C一樣的低級功能,所以不能使用臟內聯彙編技巧來加快某些操作。 這提供了可移植性,並且是現在大多數高級語言的一個功能。

  • 通常會將Java應用程序與非常舊的JVM版本綁定在一起。 尤其是服務器端。 與最新版本相比,這些舊的JVM可能效率非常低。

最終,Java被設計用來提供安全性和可移植性,但犧牲了某些性能,並且對於一些真正要求苛刻的操作。 其緩慢的聲譽大部分不應得到。

但是,有幾個地方Java比大多數其他語言更快

  • 內存分配和解除分配速度快而且便宜。 我已經看到了分配一個新的多kB陣列比使用緩存的情況快20%(或更多)的情況。

  • 對象實例化和麵向對象的特性正在快速地使用 (在某些情況下比C ++更快),因為它們從一開始就被設計出來。 這部分來自良好的GC而非明確的分配(這對更多的小對象分配更友好)。 可以編寫C的代碼(通過滾動自定義內存管理和高效地執行malloc),但這並不容易。

  • 方法調用基本上是免費的,在某些情況下比大方法代碼更快。 HotSpot編譯器使用執行信息來優化方法調用並具有非常高效的內聯。 通過使用附加的執行信息,它有時可能超過提前編譯器甚至(在極少數情況下)手動內聯。 與C / C ++相比,如果編譯器決定不內聯,那麼方法調用的性能會受到很小的影響。

  • 同步和多線程簡單而高效。 Java被設計為從一開始就是線程感知的,並且它顯示了。 現代計算機通常具有多個內核,並且因為線程內置於語言中,所以您可以非常輕鬆地利用。 與標準的單線程C代碼相比,基本上可以提高100%到300%的速度提升。 是的,認真編寫的C線程和庫可以勝過這個,但這對程序員來說是一項額外的工作。

  • 字符串包括長度:一些操作速度更快。 這使用空分隔的字符串(在C中常見)。 在Java 7中,Oracle取消了String.subString()優化,因為人們愚蠢地使用它並導致內存洩漏。

  • 陣列副本高度優化。 在最新版本中,Java為System.arraycopy使用手動調整的彙編程序。 結果是在arraycopy / memcopy-heavy操作中,我看到我的代碼以合理的利潤率勝過C中的等價物。

  • JIT編譯器在使用L1/L2緩存方面非常明智 。 提前編譯的程序不能實時調整它們的代碼到它們運行的特定CPU和系統。 JIT以這種方式提供了一些非常高效的循環轉換。

其他一些歷史事實促成了“Java很慢”的聲譽:

  • 在JIT編譯之前(Java 1.2 / 1.3),語言只能被解釋,而不能編譯,因此非常慢。
  • JIT編譯花費時間變得高效(每個版本都有重大改進)
  • 班加載多年來變得更有效率。 它在啟動過程中效率很低,速度很慢。
  • Swing和UI代碼沒有很好地使用本地圖形硬件。
  • Swing太糟糕了。 我指責AWT和Swing是為什麼Java從未在桌面上出現過。
  • 在庫類中大量使用同步; 不同步的版本現在可用
  • 小程序需要永久加載,因為通過網絡傳輸完整的JAR並加載虛擬機啟動。
  • 同步用於帶來嚴重的性能損失(這已通過每個Java版本進行了優化)。 雖然反射仍然很昂貴。

斯特凡諾:

從一開始我就一直在使用Java,所以從我的角度來看,慢速名聲是由無響應和慢速GUI前端(AWT,然後是Swing)和Applets創建的,可能是因為其啟動時間較慢VM的。

Java在VM領域已經規定並推動了很多研究,並且已經有了一些改進,包括垃圾收集(您可以實際調整很多事物;但是,我經常會看到僅使用默認值的系統)和熱點優化(在服務器端開始並且可能仍然更高效)。

後端Java和計算級別並不那麼慢。 Colt是最好的例子之一:

最新穩定的柯爾特版本打破了JDK ibm-1.4.1,RedHat 9.0,2x [email protected] GHz的1.9 Gflop / s障礙。

主流Java之外還有很多應該考慮的事情,比如Realtime Java或者像Javolution一樣提高速度的特殊機制,以及Javolution編譯(如gcj)。 此外,還有一些IC可以直接執行Java字節碼,例如當前iPhone和iPod的ARM Jazelle中的IC。

我認為,通常今天這是一個政治決定(就像iPhone / iPod上沒有Java支持一樣),並且決定反對Java作為一種語言(因為很多人認為它太冗長)。

但是,現在Java VM有很多其他語言(例如Python,Ruby,JavaScript,Groovy,Scala等),這可能是另一種選擇。

就我個人而言,我繼續享受它作為一個靈活可靠的平台,具有出色的工具和庫可用性,允許人們使用最小的設備(例如JavaCard)到最大的服務器。


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

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


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

  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應用程序的主要問題在於,由於庫運行時庫的大小很大 ,因此它很大 。 巨大的程序在內存中佔據很大的比例,並傾向於交換,這意味著它們變得緩慢。

Sun JVM很大的原因是因為它有一個非常好的字節碼解釋器,它通過跟踪很多事情來工作。 這意味著很多數據,這意味著記憶。

你可能想看看jamvm虛擬機,它是一個相當快的解釋器(非本地代碼),非常小。 它甚至開始快速。


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

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

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


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

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

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


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

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

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


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

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


對於大多數人的交互體驗 - Java 慢。 我們都看到,在一些applet出現之前,咖啡杯在我們的瀏覽器上旋轉。 啟動JVM並下載applet二進製文件需要一段時間,並且會以一種被注意到的方式影響用戶體驗。

JVM啟動和小程序下載時間慢用Java咖啡杯顯著地標記是沒有幫助的,所以人們將這種等待與Java聯繫起來。 當Flash需要很長時間才能加載時,“加載”消息的品牌由Flash開發人員指定,因此人們不會將Flash技術作為一個整體。

所有這些與Java在服務器上的性能或Java在瀏覽器外部使用的許多其他方式無關。 但是這正是人們所看到的,以及非Java開發人員在思考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的第一印象。


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


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

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


在九十年代中期Java成為主流時,C ++是主流語言,而且網絡還是相當新的。 而且,JVM和GC在主流開發中是相對較新的概念。 早期的JVM比較慢(與裸機上運行的C ++相比),而且還會因為垃圾收集時間過長而受到影響,這導致Java聲譽緩慢。


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

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

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







performance