搜尋
首頁Javajava教程關於java效能的9個謬論
關於java效能的9個謬論Nov 26, 2016 am 11:32 AM
javajava效能

Java的性能有某種黑魔法之稱。部分原因在於Java平台非常複雜,很多情況下問題難以定位。然而在歷史上還有一種趨勢,人們靠智慧和經驗來研究Java效能,而不是靠應用統計和實證推理。在這篇文章中,我希望拆穿一些最荒謬的技術神話。

1.Java很慢

關於Java的效能有很多謬論,這一條是最過時的,可能也是最為明顯的。

確實,在上世紀90年代和本世紀初處,Java有時很慢。

然而從那以後,虛擬機器和JIT技術已經有了十多年的改進,Java的整體效能現在已經非常好了。

在6個獨立的Web效能基準測試中,Java框架在24項測試中有22項位列前四。

儘管JVM利用效能剖析僅優化常用的程式碼路徑,但這種最佳化效果很明顯。很多情況下,JIT編譯的Java程式碼和C++一樣快,而且這樣的情況越來越多了。

儘管如此,還是有人認為Java平台很慢,這或許源自於體驗過Java平台早期版本的人的歷史偏見。

在下結論之前,我們建議保持客觀的態度,並且評估一下最新的性能結果。

2.可以孤立地看待單行Java程式碼

考慮下面這行短小的程式碼:

MyObject obj = new MyObject();

對Java開發者而言,看似很明顯,這行程式碼一定會分配一個物件並呼叫適當的構造器。

我們或許可以據此推出性能邊界了。我們認為這行程式碼一定會導致執行一定量的工作,基於這種推定,就可以嘗試計算其效能影響了。

其實這種認識是錯誤的,它讓我們先入為主地認為,不管什麼工作,在任何情況下都會進行。

事實上,javac和JIT編譯器都能夠將死程式碼最佳化掉。就JIT編譯器而言,基於效能剖析數據,甚至可以透過預測將程式碼最佳化掉。在這樣的情況下,這行程式碼根本不會運行,所以不會影響效能。

此外,在某些JVM中——例如JRockit——JIT編譯器甚至可以將物件上的操作分解,因此即便程式碼路徑還有效,分配操作也可以避免。

這裡的寓意是,在處理Java效能問題時,上下文非常重要,過早的最佳化有可能產生違反直覺的結果。所以最好不好太早優化。相反,應該總是建立程式碼,並且使用效能調校技術來定位效能熱點,然後加以改進。

3.微基準測試和你想像的一樣

正如我們上面看到的那樣,檢查一小段程式碼不如分析應用的整體性能來的準確。

儘管如此,開發者還是喜歡寫微基準測試。似乎對平台底層的某些方面進行修修補補會帶來無窮的樂趣。

理查德·費曼曾說過:「不要欺騙自己,你自己正是最容易被欺騙的人。」這句話用來說明編寫Java微基準測試這件事是再合適不過了。

編寫良好的微基準測試極為困難。 Java平台非常複雜,而且很多微基準測試只能用於測量瞬時效應,或是Java平台的其他意想不到的方面。

例如,如果沒有經驗,編寫的微基準測試往往就是測一下時間或垃圾收集,卻沒有抓住真正的影響因素。

只有那些有實際需求的開發者和開發團隊才應該編寫微基準測試。這些基準測試應該完全公開(包括原始碼),而且是可以復現的,還應接受同儕審查及進一步的審查。

Java平台的許多最佳化顯示統計運行和單次運行對結果影響很大。要得到真實可靠的答案,應該要將一個單獨的基準測試運行多次,然後把結果總結在一起。

如果讀者覺得有必要寫微基準測試,Georges、Buytaert和Eeckhout等人的論文《利用嚴格的統計方法評測Java 效能(Statistically Rigorous Java Performance Evaluation)》是個不錯的開始。缺乏適當的統計分析,我們容易被誤導。

有很多開發好的工具以及圍繞這些工具的社群(例如Google的Caliper)。如果確實有必要編寫微基準測試,那也不要自己寫,這時需要的是同儕的意見和經驗。

4.演算法慢是效能問題最常見的原因

在開發者之間有一個很常見的認知錯誤(普通大眾也是如此),即認為系統中他們控制的那部分很重要。

在探討Java效能時,這種認知錯誤也有所體現:Java開發者認為演算法的品質是效能問題的主要原因。開發者考慮的是程式碼,因此自然會偏向考慮自己的演算法。

實際上在處理一系列現實中的效能問題時,人們發現演算法設計是根本問題的幾率不足10%。

相反,與演算法相比,垃圾收集、資料庫存取和配置錯誤導致應用程式緩慢的可能性更大。

大部分應用處理的資料量相對較小,因此,即使主要演算法效率不高,通常也不會導致嚴重的效能問題。可以肯定,我們的演算法不是最優的;儘管如此,演算法帶來的效能問題還是算小的,更多效能問題是應用堆疊的其他部分所導致的。

因此我們的最佳建議是,使用實際生產數據來揭開效能問題的真正原因。要測量性能數據,而不是憑空猜測!

5.快取可以解決所有問題

「電腦科學中的所有問題都可以透過引入一個中間層來解決。」

David Wheeler的這句程式設計師格言(在網路上,這句話至少還被認為是其他兩位電腦科學家說的)非常常見,尤其是在Web開發者之中很流行。

如果未能透徹理解現有的架構,而且分析也已停頓,往往就是「快取可以解決所有問題」這種謬論抬頭的時候了。

在開發者看來,與其處理嚇人的現有系統,不如在前面加一層緩存,將現有系統隱藏起來,以此期待最好的情況。無疑,這種方式只是讓整體架構更複雜了,當下一個接手的開發者打算了解系統現狀時,情況會更糟。

規模龐大、設計拙劣的系統往往缺乏整體的設計,是一次一行程式碼、一個子系統這樣寫出來的。然而很多情況下,簡化並重構架構會帶來更好的效能,幾乎總是更容易讓人理解。

所以當評估是否真的有必要加入快取時,應該先計劃收集一些基本的使用統計資料(例如命中率和未命中率等),以此證明快取層帶來的真正價值。

6.所有應用都需要關注Stop-The-World問題

Java平台存在一個無法改變的事實:為運行垃圾收集,所有應用線程必須週期性停頓。有時這被當作Java的一個嚴重缺點,即使沒有任何真實憑實據。

實證研究表明,如果數字數據(如價格波動)變化的頻率超過200毫秒一次,人就無法正常感知了。

應用主要是給人用的,因此我們有一個有用的經驗法則,200毫秒或低於200毫秒的Stop-The-World(STW)通常是沒有影響的。有些應用程式可能有更高的要求(如串流媒體),但許多GUI應用程式是不需要的。

少數應用(如低延遲交易或機械控制系統)無法接受200毫秒的停頓。除非寫出來的就是這類應用,否則使用者基本上感覺不到垃圾收集器的影響。

值得一提的是,在應用執行緒數量超過實體核數的任何系統中,作業系統必須控制對CPU的分時存取。 Stop-The-World聽著可怕,但實際上任何應用(不管是JVM還是其他應用)都要面對稀缺計算資源的爭用問題。

如果不去測量,JVM對應用效能有何附加影響是不清楚的。

總之,請開啟GC日誌,以確定停頓時間是否真的影響了應用。透過分析日誌來確定停頓時間,這裡既可以手動分析,也可以利用腳本或工具分析。然後再判定它們是否真的給應用於帶來了問題。最重要的是,問自己一個關鍵的問題:確實有用戶抱怨嗎?

7.手寫物件池適合一大類應用程式

認為Stop-The-World停頓在某種程度上是不好的,應用開發團隊的一個常見反應就是在Java堆內實現自己的記憶體管理技術。這往往歸結為實現一個物件池(甚至是全面的引用計數),而且需要使用了領域物件的任何程式碼都參與其中。

這種技術幾乎總是具有誤導性的。它是基於過去的認知,那時物件分配非常昂貴,而修改物件則廉價的多。現在的情況已經完全不同了。

現在的硬體在分配時非常有效率;最新的桌面或伺服器硬件,記憶體頻寬至少是2到3GB。這是一個很大的數字,除非專門寫的應用,否則要充分利用這麼大的頻寬還真不容易。

一般來說,正確實現物件池非常困難(尤其是有多個執行緒工作時),而且物件池也帶來了一些負面的要求,使這種技術不是一個通用的良好選擇:

所有接觸到物件池程式碼的開發者必須了解物件池,而且能正確處理

哪些程式碼知道物件池,哪些程式碼不知道物件池,其界限必須讓大家知道,並且寫在文檔中

這些額外的複雜性要保持更新,而且定期復審

如果有一條不滿足,悄然出現問題(類似於C 中的指針復用)的風險就又回來了

總之,只有GC停頓不能接受,而且調校和重構也未能將停頓減小到可以接受的程度時,才能使用物件池。

8.在垃圾收集中,相對於Parallel Old,CMS總是更好的選擇

Oracle JDK默認使用一個並行的Stop-The-World收集器來收集老年代,即Parallel Old收集器。

Concurrent-Mark-Sweep (CMS)是一個替代方案,在大部分垃圾收集週期,它允許應用線程繼續運行,但這是有代價的,而且有一些注意事項。

允許應用程式執行緒與垃圾收集執行緒一起運行,不可避免地帶來一個問題:應用執行緒修改了物件圖,可能會影響物件的存活性。這種情況必須在事後加以清理,因此CMS實際上有兩個STW階段(通常非常短)。

這會帶來一些後果:

必須將所有應用線程帶到安全點,每次Full GC期間會停頓兩次;

儘管垃圾收集與應用同時執行,但應用的吞吐量會降低(通常是50%);

在使用CMS進行垃圾收集時,JVM所使用的簿記資訊(和CPU週期)遠高於其他的平行收集器。

這些代價是不是物有所值,取決於應用的情況。但是天下沒有白吃的午餐。 CMS收集器在設計上值得稱道,但它不是萬能的。

所以在確定CMS是正確的垃圾收集策略之前,首先應該確認Parallel Old的STW停頓確實不能接受,而且已經無法調校。最後,我重點強調一下,所有指標必須從與生產系統等價的系統中獲得。

9.增加堆的大小可以解決記憶體問題

當應用程式陷入困境,並且懷疑是GC的問題時,很多應用團隊的反應就是增加堆的大小。在某些情況下,這樣做可以快速見效,而且為我們留出了時間來考慮更週詳的解決方案。然而,如果沒有充分理解效能問題的原因,這種策略反而會讓事情變得更糟。

考慮一個編碼非常糟糕的應用程序,它正在產生很多領域物件 (它們的生存時間很有代表性,比如說是2-3秒)。如果分配率高到一定程度,垃圾收集會頻繁進行,這樣領域物件就會被提升到老年代。領域對象幾乎是一進入年老代,生存時間就結束了,從而直接死亡,但它們直到下一次Full GC時才會被回收。

如果增加了應用的堆大小,我們所做的不過是增加了相對短命的對象進入和死亡所使用的空間。這會導致Stop-The-World停頓時間更長,對應用並無益處。

在修改堆大小或調校其他參數之前,理解物件的分配和生存時間的動態是必要的。沒有測量性能數據就盲目行動,只會使情況更糟。在這裡,垃圾收集器的老年代分佈特別重要。

結論

當談到Java的性能調校時,直覺常常起誤導作用。我們需要實驗數據和工具來幫助我們將平台的行為視覺化並加強理解。

垃圾收集就是最好的例子。對於調校或產生指導調校的資料而言,GC子系統擁有無限的潛力;但對於產品應用而言,不使用工具很難理解所產生資料的意義。

預設情況下,執行任意Java進程(包括開發環境和產品環境),應該至少總是使用以下參數:

-verbose:gc(列印GC日誌)
-Xloggc:(更全面的GC日誌)
-XX:+PrintGCDetails(更詳細的輸出)
-XX:+PrintTenuringDistribution(顯示JVM所使用的將物件提升進入老年代的年齡閾值)

然後使用工具來分析日誌,這裡可以利用手寫的腳本,可以利用用圖生成,也可以使用GCViewer(開源的)或jClarity Censum這樣的視覺化工具。


陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
带你搞懂Java结构化数据处理开源库SPL带你搞懂Java结构化数据处理开源库SPLMay 24, 2022 pm 01:34 PM

本篇文章给大家带来了关于java的相关知识,其中主要介绍了关于结构化数据处理开源库SPL的相关问题,下面就一起来看一下java下理想的结构化数据处理类库,希望对大家有帮助。

Java集合框架之PriorityQueue优先级队列Java集合框架之PriorityQueue优先级队列Jun 09, 2022 am 11:47 AM

本篇文章给大家带来了关于java的相关知识,其中主要介绍了关于PriorityQueue优先级队列的相关知识,Java集合框架中提供了PriorityQueue和PriorityBlockingQueue两种类型的优先级队列,PriorityQueue是线程不安全的,PriorityBlockingQueue是线程安全的,下面一起来看一下,希望对大家有帮助。

完全掌握Java锁(图文解析)完全掌握Java锁(图文解析)Jun 14, 2022 am 11:47 AM

本篇文章给大家带来了关于java的相关知识,其中主要介绍了关于java锁的相关问题,包括了独占锁、悲观锁、乐观锁、共享锁等等内容,下面一起来看一下,希望对大家有帮助。

一起聊聊Java多线程之线程安全问题一起聊聊Java多线程之线程安全问题Apr 21, 2022 pm 06:17 PM

本篇文章给大家带来了关于java的相关知识,其中主要介绍了关于多线程的相关问题,包括了线程安装、线程加锁与线程不安全的原因、线程安全的标准类等等内容,希望对大家有帮助。

详细解析Java的this和super关键字详细解析Java的this和super关键字Apr 30, 2022 am 09:00 AM

本篇文章给大家带来了关于Java的相关知识,其中主要介绍了关于关键字中this和super的相关问题,以及他们的一些区别,下面一起来看一下,希望对大家有帮助。

Java基础归纳之枚举Java基础归纳之枚举May 26, 2022 am 11:50 AM

本篇文章给大家带来了关于java的相关知识,其中主要介绍了关于枚举的相关问题,包括了枚举的基本操作、集合类对枚举的支持等等内容,下面一起来看一下,希望对大家有帮助。

java中封装是什么java中封装是什么May 16, 2019 pm 06:08 PM

封装是一种信息隐藏技术,是指一种将抽象性函式接口的实现细节部分包装、隐藏起来的方法;封装可以被认为是一个保护屏障,防止指定类的代码和数据被外部类定义的代码随机访问。封装可以通过关键字private,protected和public实现。

归纳整理JAVA装饰器模式(实例详解)归纳整理JAVA装饰器模式(实例详解)May 05, 2022 pm 06:48 PM

本篇文章给大家带来了关于java的相关知识,其中主要介绍了关于设计模式的相关问题,主要将装饰器模式的相关内容,指在不改变现有对象结构的情况下,动态地给该对象增加一些职责的模式,希望对大家有帮助。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
2 週前By尊渡假赌尊渡假赌尊渡假赌
倉庫:如何復興隊友
4 週前By尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒險:如何獲得巨型種子
4 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

MantisBT

MantisBT

Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

SublimeText3 英文版

SublimeText3 英文版

推薦:為Win版本,支援程式碼提示!

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

將Eclipse與SAP NetWeaver應用伺服器整合。

Dreamweaver Mac版

Dreamweaver Mac版

視覺化網頁開發工具