鍍金池/ 教程/ Java/ JVM 類型以及編譯器模式
新生代垃圾回收
參數(shù)分類和即時(shí)(JIT)編譯器診斷
打印所有 XX 參數(shù)及值
GC 日志
JVM 類型以及編譯器模式
內(nèi)存調(diào)優(yōu)
CMS 收集器
吞吐量收集器

JVM 類型以及編譯器模式

原文地址:https://blog.codecentric.de/en/2012/07/useful-jvm-flags-part-1-jvm-types-and-compiler-modes/

現(xiàn)在的 JVM 運(yùn)行 Java 程序(和其它的兼容性語言)時(shí)在高效性和穩(wěn)定性方面做的非常出色。自適應(yīng)內(nèi)存管理、垃圾收集、及時(shí)編譯、動(dòng)態(tài)類加載、鎖優(yōu)化——這里僅僅列舉了某些場(chǎng)景下會(huì)發(fā)生的神奇的事情,但他們幾乎不會(huì)直接與普通的程序員相關(guān)。在運(yùn)行時(shí),JVM 會(huì)不斷的計(jì)算并優(yōu)化應(yīng)用或者應(yīng)用的某些部分。

雖然有了這種程度的自動(dòng)化(或者說有這么多自動(dòng)化),但是 JVM 仍然提供了足夠多的外部監(jiān)控和手動(dòng)調(diào)優(yōu)工具。在有錯(cuò)誤或低性能的情況下,JVM 必須能夠讓專家調(diào)試。順便說一句,除了這些隱藏在引擎中的神奇功能,允許大范圍的手動(dòng)調(diào)優(yōu)也是現(xiàn)代 JVM 的優(yōu)勢(shì)之一。有趣的是,一些命令行參數(shù)可以在 JVM 啟動(dòng)時(shí)傳入到 JVM 中。一些 JVM 提供了幾百個(gè)這樣的參數(shù),所以如果沒有這方面的知識(shí)很容易迷失。這系列博客的目標(biāo)是著重講解日常相關(guān)的一些參數(shù)以及他們的適用場(chǎng)合。我們將專注于 Java6 的 Sun/Oracle HotSpot jvm,大多數(shù)情況下,這些參數(shù)也會(huì)適用于其他一些流行的 JVM 里。

-server and -client

有兩種類型的 HotSpot JVM,即“server” 和“client”。服務(wù)端的 VM 中的默認(rèn)為堆提供了一個(gè)更大的空間以及一個(gè)并行的垃圾收集器,并且在運(yùn)行時(shí)可以更大程度地優(yōu)化代碼。客戶端的 VM 更加保守一些(校對(duì)注:這里作者指客戶端虛擬機(jī)有較小的默認(rèn)堆大?。?,這樣可以縮短 JVM 的啟動(dòng)時(shí)間和占用更少的內(nèi)存。有一個(gè)叫”JVM 功效學(xué)” 的概念,它會(huì)在 JVM 啟動(dòng)的時(shí)候根據(jù)可用的硬件和操作系統(tǒng)來自動(dòng)的選擇 JVM 的類型。具體的標(biāo)準(zhǔn)可以在這里找到。從標(biāo)準(zhǔn)表中,我們可以看到客戶端的 VM 只在 32 位系統(tǒng)中可用。

如果我們不喜歡預(yù)選(校對(duì)注:指 JVM 自動(dòng)選擇的 JVM 類型)的 JVM,我們可以使用 - server 和 - client 參數(shù)來設(shè)置使用服務(wù)端或客戶端的 VM。雖然當(dāng)初服務(wù)端 VM 的目標(biāo)是長時(shí)間運(yùn)行的服務(wù)進(jìn)程,但是現(xiàn)在看來,在運(yùn)行獨(dú)立應(yīng)用程序時(shí)它比客戶端 VM 有更出色的性能。當(dāng)應(yīng)用的性能非常重要時(shí),我推薦使用 - server 參數(shù)來選擇服務(wù)端 VM。一個(gè)常見的問題:在一個(gè) 32 位的系統(tǒng)上,HotSpot JDK 可以運(yùn)行服務(wù)端 VM,但是 32 位的 JRE 只能運(yùn)行客戶端 VM。

-version and -showversion

當(dāng)我們調(diào)用 “java” 命令時(shí),我們?nèi)绾尾拍苤牢覀儼惭b的是哪個(gè)版本的 Java 和 JVM 類型呢?在同一個(gè)系統(tǒng)中安裝多個(gè) Java,如果不注意的話有運(yùn)行錯(cuò)誤 JVM 的風(fēng)險(xiǎn)。在不同的 Linux 版本上預(yù)裝 JVM 這方面,我承認(rèn)現(xiàn)在已經(jīng)變的比以前好很多了。幸運(yùn)的是,我們現(xiàn)在可以使用 - version 參數(shù),它可以打印出正在使用的 JVM 的信息。例如:

$ java -version
java version "1.6.0_24"
Java(TM) SE Runtime Environment (build 1.6.0_24-b07)
Java HotSpot(TM) Client VM (build 19.1-b02, mixed mode, sharing)

輸出顯示的是 Java 版本號(hào) (1.6.0_24) 和 JRE 確切的 build 號(hào) (1.6.0_24-b07)。我們也可以看到 JVM 的名字 (HotSpot)、類型 (client) 和 build ID(19.1-b02) )。除此之外,我們還知道 JVM 以混合模式 (mixed mode) 在運(yùn)行,這是 HotSpot 默認(rèn)的運(yùn)行模式,意味著 JVM 在運(yùn)行時(shí)可以動(dòng)態(tài)的把字節(jié)碼編譯為本地代碼。我們也可以看到類數(shù)據(jù)共享(class data sharing)是開啟的,類數(shù)據(jù)共享(class data sharing)是一種在只讀緩存(在 jsa 文件中,”Java Shared Archive”)中存儲(chǔ) JRE 的系統(tǒng)類,被所有 Java 進(jìn)程的類加載器用來當(dāng)做共享資源。類數(shù)據(jù)共享 (Class data sharing) 可能在經(jīng)常從 jar 文檔中讀所有的類數(shù)據(jù)的情況下顯示出性能優(yōu)勢(shì)。

-version 參數(shù)在打印完上述信息后立即終止 JVM。還有一個(gè)類似的參數(shù) - showversion 可以用來輸出相同的信息,但是 - showversion 緊接著會(huì)處理并執(zhí)行 Java 程序。因此,-showversion 對(duì)幾乎所有 Java 應(yīng)用的命令行都是一個(gè)有效的補(bǔ)充。你永遠(yuǎn)不知道你什么時(shí)候,突然需要了解一個(gè)特定的 Java 應(yīng)用(崩潰時(shí))使用的 JVM 的一些信息。在啟動(dòng)時(shí)添加 -showversion,我們就能保證當(dāng)我們需要時(shí)可以得到這些信息。

-Xint, -Xcomp, 和 -Xmixed

-Xint 和 -Xcomp 參數(shù)和我們的日常工作不是很相關(guān),但是我非常有興趣通過它來了解下 JVM。在解釋模式 (interpreted mode) 下,-Xint 標(biāo)記會(huì)強(qiáng)制 JVM 執(zhí)行所有的字節(jié)碼,當(dāng)然這會(huì)降低運(yùn)行速度,通常低 10 倍或更多。-Xcomp 參數(shù)與它(-Xint)正好相反,JVM 在第一次使用時(shí)會(huì)把所有的字節(jié)碼編譯成本地代碼,從而帶來最大程度的優(yōu)化。這聽起來不錯(cuò),因?yàn)檫@完全繞開了緩慢的解釋器。然而,很多應(yīng)用在使用 - Xcomp 也會(huì)有一些性能損失,當(dāng)然這比使用 - Xint 損失的少,原因是 - xcomp 沒有讓 JVM 啟用 JIT 編譯器的全部功能。JIT 編譯器在運(yùn)行時(shí)創(chuàng)建方法使用文件,然后一步一步的優(yōu)化每一個(gè)方法,有時(shí)候會(huì)主動(dòng)的優(yōu)化應(yīng)用的行為。這些優(yōu)化技術(shù),比如,積極的分支預(yù)測(cè)(optimistic branch prediction),如果不先分析應(yīng)用就不能有效的使用。另一方面方法只有證明它們與此相關(guān)時(shí)才會(huì)被編譯,也就是,在應(yīng)用中構(gòu)建某種熱點(diǎn)。被調(diào)用很少(甚至只有一次)的方法在解釋模式下會(huì)繼續(xù)執(zhí)行,從而減少編譯和優(yōu)化成本。

注意混合模式也有他自己的參數(shù),-Xmixed。最新版本的 HotSpot 的默認(rèn)模式是混合模式,所以我們不需要特別指定這個(gè)標(biāo)記。我們來用對(duì)象填充 HashMap 然后檢索它的結(jié)果做一個(gè)簡單的用例。每一個(gè)例子,它的運(yùn)行時(shí)間都是很多次運(yùn)行的平均時(shí)間。

$ java -server -showversion Benchmark
java version "1.6.0_24"
Java(TM) SE Runtime Environment (build 1.6.0_24-b07)
Java HotSpot(TM) Server VM (build 19.1-b02, mixed mode)

Average time: 0.856449 seconds
$ java -server -showversion -Xcomp Benchmark
java version "1.6.0_24"
Java(TM) SE Runtime Environment (build 1.6.0_24-b07)
Java HotSpot(TM) Server VM (build 19.1-b02, compiled mode)

Average time: 0.950892 seconds
$ java -server -showversion -Xint Benchmark
java version "1.6.0_24"
Java(TM) SE Runtime Environment (build 1.6.0_24-b07)
Java HotSpot(TM) Server VM (build 19.1-b02, interpreted mode)

Average time: 7.622285 seconds

當(dāng)然也有很多使 - Xcomp 表現(xiàn)很好的例子。特別是運(yùn)行時(shí)間長的應(yīng)用,我強(qiáng)烈建議大家使用 JVM 的默認(rèn)設(shè)置,讓 JIT 編譯器充分發(fā)揮其動(dòng)態(tài)潛力,畢竟 JIT 編譯器是組成 JVM 最重要的組件之一。事實(shí)上,正是因?yàn)?JVM 在這方面的進(jìn)展才讓 Java 不再那么慢。

下一篇:CMS 收集器