讓Java應(yīng)用程序運(yùn)行是一回事,但讓他們跑得快就是另外一回事了。在面對(duì)對(duì)象的環(huán)境中,性能問(wèn)題就像來(lái)勢(shì)兇猛的野獸。但JVM的復(fù)雜性將性能調(diào)整的復(fù)雜程度增加了一個(gè)級(jí)別。這里Refcard涵蓋了JVM internals、class loading(Java8中更新以映射最新的元空間)、垃圾回收、故障診斷、檢測(cè)、并發(fā)性,等等。
性能測(cè)試工具 Loadrunner
點(diǎn)擊下載
介紹
Java是目前軟件開(kāi)發(fā)領(lǐng)域中使用最廣泛的編程語(yǔ)言之一。Java應(yīng)用程序在許多垂直領(lǐng)域(銀行、電信、醫(yī)療保健等)中都有廣泛使用。Refcard的目的是,幫助開(kāi)發(fā)者通過(guò)專(zhuān)注于JVM內(nèi)部,性能調(diào)整原則和最佳實(shí)踐,以及利用現(xiàn)有監(jiān)測(cè)和故障診斷工具,來(lái)提升應(yīng)用程序在商業(yè)環(huán)境中的性能。
它能以不同的方式定義“optimal performance(最佳性能)”,但基本要素是:Java程序在業(yè)務(wù)響應(yīng)時(shí)間要求內(nèi)執(zhí)行計(jì)算任務(wù)的能力,程序在高容量下執(zhí)行業(yè)務(wù)功能的能力,并具有可靠性高和延遲低的特點(diǎn)。有時(shí),數(shù)字本身變得模式化:對(duì)于一些大型網(wǎng)站,優(yōu)秀的頁(yè)面響應(yīng)時(shí)間應(yīng)該在500ms以下。在適當(dāng)?shù)臅r(shí)候,Refcard包括目標(biāo)數(shù)字。但在大多數(shù)情況下,您需要根據(jù)業(yè)務(wù)需求和現(xiàn)有的性能基準(zhǔn)自己決定這些。
JVM Internals
基礎(chǔ)知識(shí)

代碼編譯和JIT
編譯Java字節(jié)碼顯然沒(méi)有直接從主機(jī)執(zhí)行本機(jī)代碼那么快。為了提高性能,Hotspot JVM找出最繁忙的字節(jié)碼區(qū)域,然后將其編譯成更高效地原生、機(jī)器代碼(自適應(yīng)優(yōu)化)。然后這種本地代碼就會(huì)存儲(chǔ)在非堆內(nèi)存中的代碼緩存中。
注意:多數(shù)的JVM是通過(guò)禁用JIT編譯器實(shí)現(xiàn)的(Djava.compiler=NONE)。您只需要考慮禁用的關(guān)鍵性?xún)?yōu)化,比如JVM崩潰。
下圖說(shuō)明了Java源代碼,即時(shí)編譯流程和生命周期。

內(nèi)存空間
HotSpot Java Virtual Machine是由以下的存儲(chǔ)空間組成。
存儲(chǔ)空間描述Java HeapJava程序類(lèi)實(shí)例和數(shù)組的主存儲(chǔ)器。Permanent Generation(JDK 1.7及以下版本)Metaspace (JDK 1.8及以上版本)Java類(lèi)元數(shù)據(jù)的主存儲(chǔ)器。注意:從Java 8開(kāi)始,PermGen空間就由元空間和使用本地存儲(chǔ)器替換了,類(lèi)似于IBM J9 JVM。Native Heap(C-Heap)本地內(nèi)存存儲(chǔ)線程、棧、包括對(duì)象的代碼緩存,如MMAP文件和第三方本機(jī)庫(kù)。類(lèi)加載
Java的另一個(gè)重要特點(diǎn)是,在JVM啟動(dòng)之后,它能夠加載編譯的Java類(lèi)(字節(jié)碼)。根據(jù)程序的大小,在剛剛重啟之后,程序在類(lèi)加載過(guò)程中性能會(huì)顯著降低。這種現(xiàn)象是因?yàn)閮?nèi)部JIT編譯器在重啟之后需要重新開(kāi)始優(yōu)化。
自JDK 1.7版本之后,有一些改進(jìn)值得大家重視。例如默認(rèn)的JDK class loader具有更好的裝在類(lèi)并發(fā)能力。
熱點(diǎn)
關(guān)注的區(qū)域建議JVM重啟后的性能下降避免部署過(guò)量的Java類(lèi)到一個(gè)單一的應(yīng)用程序類(lèi)加載器(例如:非常大的WAR文件)運(yùn)行時(shí)發(fā)現(xiàn)過(guò)多的類(lèi)加載爭(zhēng)奪(thread lock, JAR file searches…) ,降低了整體性能。分析您的應(yīng)用程序并識(shí)別代碼模塊進(jìn)行動(dòng)態(tài)類(lèi)加載操作過(guò)于頻繁。積極尋找非一站式類(lèi)加載錯(cuò)誤,如ClassNotFoundException和NoClassDefFoundError。再訪Java映射API和適用情況下優(yōu)化的過(guò)度使用。java.lang.OutOfMemoryError: PermGen space (JDK 1.7及以下版本)java.lang.OutOfMemoryError:元空間(JDK 1.8及以上版本)再訪JVM Permanent Generation、Metaspace (MaxMetaSpaceSize)和本地內(nèi)存容量在適用情況下的尺寸。分析應(yīng)用程序類(lèi)加載器和識(shí)別元數(shù)據(jù)的內(nèi)存泄漏的源頭。
故障診斷和監(jiān)視
目標(biāo)建議跟蹤那些加載到不同的類(lèi)加載器的Java類(lèi)。配置程序選擇使用的Java profiler,例如JProfiler或Java VisualVM。將重點(diǎn)放在類(lèi)加載器的操作和內(nèi)存占用上??梢酝ㄟ^(guò)–verbose:class. for the IBM JVM,生成多個(gè)Java核心快照跟蹤活動(dòng)的類(lèi)加載器和加載類(lèi)。調(diào)查類(lèi)元數(shù)據(jù)的內(nèi)存泄露的可以來(lái)源。配置程序和定義可能的culprit(s)。生成并分析JVmheap dump快照,專(zhuān)注于類(lèi)加載器和java.lang.Class中的實(shí)例。#FormatImgID_3#確保適當(dāng)?shù)腜ermanent Generation / Metaspace和本地內(nèi)存大小。密切監(jiān)視你的PermGen、元空間和本機(jī)內(nèi)存利用率,并調(diào)整到適合的最大容量。分析程序類(lèi)加載器的大小,并尋找機(jī)會(huì)適當(dāng)?shù)販p少元數(shù)據(jù)足跡。