讓Java應用程序運行是一回事,但讓他們跑得快就是另一回事了。在面對對象的環境中,性能問題就像來勢兇猛的野獸。但JVM的複雜性將性能調整的複雜程度增長了一個級別。這裏Refcard涵蓋了JVM internals、class loading(Java8中更新以映射最新的元空間)、垃圾回收、故障診斷、檢測、併發性,等等。html
Java是目前軟件開發領域中使用最普遍的編程語言之一。Java應用程序在許多垂直領域(銀行、電信、醫療保健等)中都有普遍使用。Refcard的目的是,幫助開發者經過專一於JVM內部,性能調整原則和最佳實踐,以及利用現有監測和故障診斷工具,來提高應用程序在商業環境中的性能。java
它能以不一樣的方式定義「optimal performance(最佳性能)」,但基本要素是:Java程序在業務響應時間要求內執行計算任務的能力,程序在高容量下執行業務功能的能力,並具備可靠性高和延遲低的特色。有時,數字自己變得模式化:對於一些大型網站,優秀的頁面響應時間應該在500ms如下。在適當的時候,Refcard包括目標數字。但在大多數狀況下,您須要根據業務需求和現有的性能基準本身決定這些。git
編譯Java字節碼顯然沒有直接從主機執行本機代碼那麼快。爲了提升性能,Hotspot JVM找出最繁忙的字節碼區域,而後將其編譯成更高效地原生、機器代碼(自適應優化)。而後這種本地代碼就會存儲在非堆內存中的代碼緩存中。apache
注意:多數的JVM是經過禁用JIT編譯器實現的(Djava.compiler=NONE)。您只須要考慮禁用的關鍵性優化,好比JVM崩潰。編程
下圖說明了Java源代碼,即時編譯流程和生命週期。windows
HotSpot Java Virtual Machine是由如下的存儲空間組成。數組
存儲空間 | 描述 |
Java Heap | Java程序類實例和數組的主存儲器。 |
Permanent Generation(JDK 1.7及如下版本)Metaspace (JDK 1.8及以上版本) | Java類元數據的主存儲器。注意:從Java 8開始,PermGen空間就由元空間和使用本地存儲器替換了,相似於IBM J9 JVM。 |
Native Heap(C-Heap) | 本地內存存儲線程、棧、包括對象的代碼緩存,如MMAP文件和第三方本機庫。 |
Java的另外一個重要特色是,在JVM啓動以後,它可以加載編譯的Java類(字節碼)。根據程序的大小,在剛剛重啓以後,程序在類加載過程當中性能會顯著下降。這種現象是由於內部JIT編譯器在重啓以後須要從新開始優化。緩存
自JDK 1.7版本以後,有一些改進值得你們重視。例如默認的JDK class loader具備更好的裝在類併發能力。安全
關注的區域 | 建議 |
JVM重啓後的性能降低 | 避免部署過量的Java類到一個單一的應用程序類加載器(例如:很是大的WAR文件) |
運行時發現過多的類加載爭奪(thread lock, JAR file searches…) ,下降了總體性能。 | 分析您的應用程序並識別代碼模塊進行動態類加載操做過於頻繁。積極尋找非一站式類加載錯誤,如ClassNotFoundException和NoClassDefFoundError。再訪Java映射API和適用狀況下優化的過分使用。 |
java.lang.OutOfMemoryError: PermGen space (JDK 1.7及如下版本)java.lang.OutOfMemoryError:元空間(JDK 1.8及以上版本) | 再訪JVM Permanent Generation、Metaspace (MaxMetaSpaceSize)和本地內存容量在適用狀況下的尺寸。分析應用程序類加載器和識別元數據的內存泄漏的源頭。 |
目標 | 建議 |
跟蹤那些加載到不一樣的類加載器的Java類。 | 配置程序選擇使用的Java profiler,例如JProfiler或Java VisualVM。將重點放在類加載器的操做和內存佔用上。能夠經過–verbose:class. for the IBM JVM,生成多個Java核心快照跟蹤活動的類加載器和加載類。 |
調查類元數據的內存泄露的能夠來源。 | 配置程序和定義可能的culprit(s)。生成並分析JVmheap dump快照,專一於類加載器和java.lang.Class中的實例。
|
確保適當的Permanent Generation / Metaspace和本地內存大小。 | 密切監視你的PermGen、元空間和本機內存利用率,並調整到適合的最大容量。分析程序類加載器的大小,並尋找機會適當地減小元數據足跡。 |
Java垃圾回收流程對於程序性能是相當重要的。爲了提供有效的垃圾回收,Heap(堆)本質上是劃分在子區域中。併發
區域 | 描述 |
最新一代-Young Generation (nursery space) | 新的或短暫的對象分配保留堆的一部分。垃圾被一個fast but stop-the-world YG的收集器進行回收。
在young space中呆了足夠久的對象就會提高到old space。 注意:YG space的尺寸和GC頻率太高將會顯著影響程序的響應時間,從而致使JVM的暫停時間增長。 |
老一代-Old Generation (tenured space) | heap的一部分留給了long-lived對象。垃圾一般經過平行或併發(多數時候)進行收集,諸如CMS或gencon (IBM JVM)。
性能提示:根據應用程序的需求選擇並測試最佳的GC策略是很是重要的。例如,當切換到併發GC收集(如CMS或G1)能夠顯著提升應用程序的平均響應時間(減小延遲)。 |
選擇正確的collector或GC policy能夠將程序的性能、可擴展性和可靠性優化到最佳狀態。許多應用程序對於響應時間延遲都很敏感,所以大多須要使用併發的回收器,例如HotSpot CMS或IBM GC policy balanced。
咱們強烈建議您經過適當的性能和負載測試肯定最合適的GC策略。應該在生產環境中執行全面監控策略,以跟蹤總體的JVM性能,並肯定在以後須要改進的領域。
GC | 論據 | 描述 |
串行回收器 | -XX:+UseSerialGC (Oracle HotSpot) | 不管新舊回收器都使用單獨CPU,像是一種stop the world的時尚。
|
並行回收器(吞吐量回收器) | -XX:+UseParallelGC-XX:+UseParallelOldGC (Oracle Hotspot)
-Xgcpolicy:optthruput |
旨在利用CPU的內核優點。不管新舊回收器都使用多個Gcthreads(via –XX:ParallelGCThreads=n),從而更好地利用來自主機的可用的CPU內核來完成。注意:雖然回收時間能夠顯著減小,可是有着大尺寸堆的程序面臨着large、stop-the-world、old回收,而且響應時間也受到影響。
|
確保適當的Permanent Generation / Metaspace和本地內存大小。 | 密切監視你的PermGen、元空間和本機內存利用率,並調整到適合的最大容量。分析程序類加載器的大小,並尋找機會適當地減小元數據足跡。 | 旨在最大限度地減小舊一代stop-the-world回收器對程序響應時間的影響。大多數使用CMS collector的老一代回收器與所述應用程序的執行同時進行。
注意:YoungGen collections仍然有stop-the-world事件,所以須要適當的微調,以減小總JVM暫停時間。 |
HotSpot G1 collector是專爲是專爲知足用戶定義的垃圾回收(GC)高几率暫停時間設計的,同時實現高吞吐量。
最新的HotSpot collector將heap基本劃分到一組大小相等的堆區域,虛擬內存的每一個區域連續範圍。它將回收壓縮的活動集中在heap區域,那裏充滿了可回收的對象(garbage first)。換句話說就是,這個區域有最低限度的「live」對象。
Oracle建議在如下例子和狀況下使用G1 collector,尤爲是對於目前正在使用CMS或parallel collectors的:
你必定要知道沒有GC策略能夠挽救Java Heap尺寸不足的現象。這些演習涉及到爲不一樣的存儲空間(包括新舊不一樣的版本)配置最大和最小的容量,包括元數據和本地內存容量。這裏有一些建議準則:
目標 | 建議 |
內存大小GC調整
監控和故障排除 |
默認狀況下,元空間內存空間是無界的,並使用可用於動態擴展的process或OS native memory。內存空間分紅快並經過mmap被JVM進行存儲。咱們建議保持默認設置,以動態調整模式爲出發點,將簡化的尺寸與密切監測的應用程序元數據佔有量相結合,從而進行更好的容量規劃。新增一個JVM選項(-XX:MaxMetaspaceSize=<NNN>),可讓您限制分配給class metadata的本地內存。當面臨物理資源(RAM)緊張或相似於內存泄露的狀況時,建議將它做爲一個保障機制。
對那種具備larger class metadata footprint或dynamic classloading的Java應用程序,咱們建議經過新的JVM選項調整初始元空間大小 :-XX:MetaspaceSize=<NNN>,例如:1GB。這種調整方法將有助於避免包括class metadata在內的早期垃圾回收,尤爲是在Java應用程序的 「warm-up」期。 |
目標 | 建議 |
測量和監視應用程序YoungGen和OldGen內存佔用,包括GC活動。爲您的應用程序決定正確的GC策略和Java堆大小。
調整應用程序的內存佔用量,如live對象。 |
分析、監控您所使用的Java分析工具,如JProfiler、Java VisualVM或其餘商業APM產品。容許經過–verbose:gc記錄JVM GC活動。您也可使用相似GCMV(GC Memory Visualizer)的工具查看JVM的暫停時間和內存分配率。
性能提示:過多的內存分配率可能意味着須要進行垂直和橫向擴展,或從多個JVM進程中分離出實時數據。 爲了long-lived對象或long-term實時數據考慮,能夠生成並分析JVM heap dump快照。Heap dump分析對於程序內存佔用(retention)的優化是很是有幫助的。 性能提示:因爲從32位到64位,Java應用程序對heap 的需求會比原來高1.5倍。因此,在Java 1.7及如下的版本(這是默認的)中使用 -XX:+UseCompressedOops是很是重要的。這樣的參數調整大大減輕了64位JVM的性能壓力。 |
調查OutOfMemoryError 問題,尋找OldGen內存泄露的根源。 | 使用相似Java VisualVM、Plumbr的工具(Java內存泄漏檢測器),分析可能存在的內容泄露。性能提示:要着重分析最大的Java對象上。要意識到下降內存佔有量就意味着提高性能,並下降GC活動。
使用相似 Memory Analyzer的工具生成並分析JVM heap dump快照。 |
Java併發性能夠定義爲程序同時執行多個任務的能力。對於大型的Java EE系統,這意味着執行多個用戶的業務功能的同時,實現最佳的吞吐量和性能的能力。
不管是硬件能力仍是JVM穩定情況,Java併發性問題可能引發程序的癱瘓,嚴重影響程序的總體性能和可用性。
當您評估Java應用程序的併發線程的穩定情況時,你會常常遇到Thread lock contention的問題,這是目前最多見的Java併發問題。
例如:Thread lock contention會觸發non-stop,它會嘗試將一個缺乏Java類(ClassNotFoundException的)加載到默認的JDK 1.7 ClassLoader。
若是您在成熟的技術環境中碰見像Thread Dump analysis這樣的問題,咱們強烈建議您積極面對它。這個問題的根源一般不一樣於以前的Java synchronization to legitimate IO blocking或者其餘的non-thread safe calls。Lock contention問題每每是另外一個問題的「症狀」。
真正的Java-level deadlocks是不太常見的,它一樣能夠極大程度地影響應用程序的性能和穩定性。當遇到兩個或多個線程永遠阻塞的時候,就會觸發這樣的問題。這種狀況不一樣於其餘常見的那種「day-to-day」線程問題,例如 lock contention、threads waiting on blocking IO calls等等。真正的lock-ordering deadlock問題能夠被看作以下:
Oracle HotSpot 和IBM JVM爲大多數的deadlock detectors狀況提供瞭解決方案,幫助您快速找出形成這種情況的罪魁禍首的線程。遇到相似lock contention troubleshooting的問題,建議從諸如線程轉儲分析爲出發點來解決該問題。
一旦找到形成問題的代碼根源,解決方案涉及lock-ordering條件尋址和來自JDK其餘可用的併發編程技術,如java.util.concurrent.locks.ReentrantLock,提供了諸如tryLock()的方法。這種方法給予開發人員更大的靈活性,也爲防止deadlock和thread lock 「starvation」提供了更多方式。
在進行JVM調優的同時,也有必要檢查應用程序的行爲,更確切地說是最高clock time和CPU burn的貢獻者。
當Java垃圾回收和線程併發再也不是壓力點,深刻到你的應用程序代碼的執行模式,並專一於頂級響應時間貢獻者(也叫做clock time)是很重要的。檢查應用程序代碼的消CPU耗和Java 線程(CPU burn)也一樣相當重要。CPU使用率較高(>75%)是不正常的(良好的物理資源的利用率)。由於這每每意味着效率低下和容量問題。對於大型的Java EE企業應用,保持安全的CPU緩衝區是必要的,以應對突發的負載衝擊狀況。
摒棄那些傳統的跟蹤方法,如在代碼中加入響應時間「日誌」。Java剖析工具和APM解決方案偏偏能夠幫助您分析這類型的問題。這種方式更加高效、可靠。對於Java生產環境缺少一個強大的APM解決方案。您仍然能夠依賴諸如Java VisualVM的工具,經過多個快照進行thread dump分析,並使用OS CPU分析每一個線程。
最後的建議是,不要妄圖同時解決全部的問題。列出排在最前面的5個clock time和CPU burn問題,而後尋找解決方案。
其餘關於Java應用程序性能的重要方面是穩定性和可靠性。在有着99.9%典型可用目標的SLA umbrella下,穩定和可靠對於程序的操做尤其重要。這些系統應該具備高容錯級別,並對應用和資源進行嚴格的預算,以防止發生多米諾效應。用這種方法能夠防止一些這樣的狀況,例如,一個業務流程使用全部可用的物理,中間件或JVM資源。
Java application與外部系統之間缺少合理的超時時間,因爲中間件和JVM線程消耗(blocking IO calls),可能致使嚴重的性能降低和中斷。合理的超時時間能夠避免在遇到外部服務提供商速度緩慢的時候,Java線程等待過久。
目標 | 建議工具 |
自動、實時地性能監控、調節、預警、趨勢分析、容量管理,等等 | Enterprise APM solutions(企業級APM解決方案)注意:APM解決方案提供了工具,這些現成的功能讓您實現如下大部分的Java性能目標。 |
性能和負載測試 | 商業性能測試解決方案Apache JMeter
|
JVM垃圾回收評估,內存分配率和故障排除 | Oracle Java VisualVMhttp://docs.oracle.com/javase/8/docs/technotes/guides/visualvm/intro.html
http://java.dzone.com/articles/profile-your-applications-java http://www.oracle.com/technetwork/java/javase/jmc53-release-notes-2157171.html IBM Monitoring and Diagnostic Tools for Java (via IBM Support Assistant tool) http://www-01.ibm.com/software/support/isa/ JVM verbose:gc logs JVM argument : -verbose:gc http://docs.oracle.com/javase/8/docs/technotes/tools/windows/java.html IBM GCMV |
JVM堆和類的元數據的內存泄漏分析 | Oracle Java VisualVM and Oracle Java Mission ControlIBM Monitoring and Diagnostic Tools for Java
Memory Analyzer (heap dump analysis, hprof and phd formats) https://www.ibm.com/developerworks/java/jdk/tools/memoryanalyzer/ |
JVM內存分析和堆容量評估 | Oracle Java VisualVM and Java Mission ControlIBM Monitoring and Diagnostic Tools for Java
Java profilers (JProfiler, YourKit) http://en.wikipedia.org/wiki/JProfiler Memory Analyzer (heap dump and application memory footprint analysis) |
JVM和中間件併發故障,如thread lock contention和deadlocks | Oracle Java VisualVM and Oracle Java Mission Control (threads monitoring, thread dump snapshots)jstack, native OS signal such as kill -3 (thread dump snapshots)
http://www.oracle.com/technetwork/java/javase/tooldescr-136044.html#gblfh IBM Monitoring and Diagnostic Tools for Java 注意:強烈推薦你們關注如何執行一個JVM線程轉儲分析的相關知識。 |
Java應用程序clock time分析和評測 | Oracle Java VisualVM and Oracle Java Mission Control (build-in profiler, sampler and recorder)Java profilers (JProfiler, YourKit) |
Java應用程序和線程CPU burn分析 | Oracle Java VisualVM and Oracle Java Mission Control (CPU profiler)Java profilers (JProfiler, YourKit)
注意:必要的時候,您還能夠依賴JVM線程轉儲和OS CPU每一個線程分析。 |
Java IO和remoting contention分析,包括超時管理評估和調整 | Oracle Java VisualVM and Oracle Java Mission Control(threads monitoring, thread dump snapshots)
jstack, native OS signal such as kill -3 (thread dump snapshots) IBM Monitoring and Diagnostic Tools for Java 注意:強烈推薦你們關注如何執行一個JVM線程轉儲分析的相關知識。 |
中間件,Java EE容器調整,如線程、JDBC數據源,等等 | Oracle Java VisualVM and Oracle Java Mission Control (extra focus on exposed Java EE container runtime MBeans)Java EE container administration and management console |