本文討論的選項(xiàng)是針對(duì)HotSpot虛擬機(jī)的。 1、選項(xiàng)分類及語(yǔ)法HotspotJVM提供以下三大類選項(xiàng): 1.1,、標(biāo)準(zhǔn)選項(xiàng)這類選項(xiàng)的功能是很穩(wěn)定的,,在后續(xù)版本中也不太會(huì)發(fā)生變化。 運(yùn)行java或者 java -help 可以看到所有的標(biāo)準(zhǔn)選項(xiàng),。 語(yǔ)法:所有的標(biāo)準(zhǔn)選項(xiàng)都是以 - 開(kāi)頭,,比如-version,-server等,。 1.2,、X選項(xiàng)這類選項(xiàng)的功能還是很穩(wěn)定,但官方的說(shuō)法是它們的行為可能會(huì)在后續(xù)版本中改變,,也有可能不在后續(xù)版本中提供了. 運(yùn)行 java-X 命令可以看到所有的X選項(xiàng),。 語(yǔ)法:這類選項(xiàng)都是以 -X 開(kāi)頭,比如-Xms,。 1.3,、XX選項(xiàng)這類選項(xiàng)是屬于實(shí)驗(yàn)性,主要是給JVM開(kāi)發(fā)者用于開(kāi)發(fā)和調(diào)試JVM的,,在后續(xù)的版本中行為有可能會(huì)變化,。 語(yǔ)法:
2、常用配置2.1,、指定JVM運(yùn)行模式Hotspot JVM有兩種類型,,分別是server和client。 它們的區(qū)別是Server VM的初始堆空間會(huì)大一些,,默認(rèn)使用的是并行垃圾回收器,,啟動(dòng)慢運(yùn)行快。Client VM相對(duì)來(lái)講會(huì)保守一些,,初始堆空間會(huì)小一些,,使用串行的垃圾回收器,它的目標(biāo)是為了讓JVM的啟動(dòng)速度更快,,但運(yùn)行速度會(huì)比Serverm模式慢些,。 JVM在啟動(dòng)的時(shí)候會(huì)根據(jù)硬件和操作系統(tǒng)自動(dòng)選擇使用Server還是Client類型的JVM。
更多詳細(xì)內(nèi)容可參見(jiàn):http://docs.oracle.com/javase/7/docs/technotes/guides/vm/server-class.html
2.2,、指定JIT編譯器模式Java是一種解釋型語(yǔ)言,但隨著JIT技術(shù)的進(jìn)步,,它能在運(yùn)行時(shí)將Java的字節(jié)碼編譯成本地代碼,。以下是幾個(gè)相關(guān)的選項(xiàng):
-Xcomp和-Xmixed到底誰(shuí)的速度快,針對(duì)不同的程序可能有不同的結(jié)果,,基本還是推薦用默認(rèn)模式,。
2.3,、查看Java版本-version和-showversion -version用于查看當(dāng)前在使用什么版本的java及JRE、什么類型的JVM(Server/Client),、采用什么編譯器模式,。示例如下: C:\Users\zsm>java -version java version "1.8.0_45" Java(TM) SE Runtime Environment (build 1.8.0_45-b14) Java HotSpot(TM) 64-Bit Server VM (build 25.45-b02, mixed mode) -showversion的作用是在運(yùn)行一個(gè)程序時(shí)首先把上述信息打印出來(lái),這樣便于問(wèn)題診斷,。 建議Server類型的程序都把-showversion選項(xiàng)打開(kāi),,這樣可以發(fā)現(xiàn)一些配置問(wèn)題,比如程序需要JDK1.7才能運(yùn)行,,而有的機(jī)器上裝有多個(gè)JDK的版本,,打開(kāi)這個(gè)選項(xiàng)可以避免使用了錯(cuò)誤版本的Java。
2.4,、打印設(shè)置的XX選項(xiàng)及值有三個(gè)選項(xiàng):-XX:+PrintCommandLineFlags,、-XX:+PrintFlagsInitial、-XX:+PrintFlagsFinal -XX:+PrintCommandLineFlags:與-showversion類似,,此選項(xiàng)可以在程序運(yùn)行時(shí)首先打印出用戶手動(dòng)設(shè)置或者JVM自動(dòng)設(shè)置的XX選項(xiàng),,建議加上這個(gè)選項(xiàng)以輔助問(wèn)題診斷。 如下示例顯示了JVM自動(dòng)配置的初始和最大的HeapSize以及其他的一些選項(xiàng): C:\Users\zsm>java -XX:+PrintCommandLineFlags -version -XX:InitialHeapSize=132712832 -XX:MaxHeapSize=2123405312 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC java version "1.8.0_45" Java(TM) SE Runtime Environment (build 1.8.0_45-b14) Java HotSpot(TM) 64-Bit Server VM (build 25.45-b02, mixed mode) -XX:+PrintFlagsInitial:表示打印出所有XX選項(xiàng)的默認(rèn)值,。示例如下:
View Code
-XX:+PrintFlagsFinal:表示打印出XX選項(xiàng)在運(yùn)行程序時(shí)生效的值。示例如下:
View Code
2.5,、各區(qū)域內(nèi)存大小設(shè)置注:虛擬機(jī)啟動(dòng)時(shí)就會(huì)把參數(shù)中設(shè)定大小的內(nèi)存全部劃為私有,,即使擴(kuò)容前有一部分內(nèi)存不會(huì)被用戶代碼用到,這部分內(nèi)存也不會(huì)交給其他進(jìn)程使用,。 2.5.1,、方法區(qū) 永久代(Java8之前,Java8中沒(méi)有永久代概念,,下面參數(shù)無(wú)效) -XX:PermSize=256m:設(shè)置永久代初始值為256M,。 -XX:MaxPermSize=256m:設(shè)置永久代最大值為256M。(同上) 元空間(Java8中) -XX:MetaspaceSize,,初始空間大小,,達(dá)到該值就會(huì)觸發(fā)垃圾收集器進(jìn)行類型卸載,同時(shí)GC會(huì)對(duì)該值進(jìn)行調(diào)整:如果釋放了大量的空間,,就適當(dāng)降低該值,;如果釋放了很少的空間,那么在不超過(guò)MaxMetaspaceSize時(shí),,適當(dāng)提高該值 -XX:MaxMetaspaceSize,,最大空間,默認(rèn)沒(méi)有限制,。 2.5.2,、棧 -Xss128k:設(shè)置每個(gè)線程的棧大小,。JDK5.0以后每個(gè)線程棧大小為1M,之前每個(gè)線程棧大小為256K,。應(yīng)當(dāng)根據(jù)應(yīng)用的線程所需內(nèi)存大小進(jìn)行調(diào)整,。在相同物理內(nèi)存下,減小這個(gè)值能生成更多的線程,。但是操作系統(tǒng)對(duì)一個(gè)進(jìn)程內(nèi)的線程數(shù)還是有限制的,,不能無(wú)限生成,經(jīng)驗(yàn)值在3000~5000左右,。需要注意的是:當(dāng)這個(gè)值被設(shè)置的較大(例如>2MB)時(shí)將會(huì)在很大程度上降低系統(tǒng)的性能,。 2.5.3、堆 -Xmx3550m:等價(jià)于-XX:MaxHeapSize,,設(shè)置JVM最大堆內(nèi)存為3550M,。 -Xms3550m:等價(jià)于-XX:InitialHeapSize,設(shè)置JVM初始堆內(nèi)存為3550M,。此值可以設(shè)置與-Xmx相同,,以避免每次垃圾回收完成后JVM重新分配內(nèi)存。 -Xmn2g:設(shè)置年輕代大小為2G,。在整個(gè)堆內(nèi)存大小確定的情況下,,增大年輕代將會(huì)減小年老代,反之亦然,。此值關(guān)系到JVM垃圾回收,,對(duì)系統(tǒng)性能影響較大,官方推薦配置為整個(gè)堆大小的3/8,。 -XX:NewSize=1024m:設(shè)置年輕代初始值為1024M,。 -XX:MaxNewSize=1024m:設(shè)置年輕代最大值為1024M。 -XX:SurvivorRatio=4:設(shè)置年輕代中Eden區(qū)與一個(gè)Survivor區(qū)的比值,。表示Edgen為一個(gè)Survivor的4倍,,即1個(gè)Survivor區(qū)占整個(gè)年輕代大小的1/6。 -XX:NewRatio=4:設(shè)置老年代與年輕代(包括1個(gè)Eden和2個(gè)Survivor區(qū))的比值,。表示老年代是年輕代的4倍,。 -XX:PretenureSizeThreadshold=1024:設(shè)置讓大于此閾值的對(duì)象直接分配在老年代(只對(duì)Serial、ParNew收集器有效),,單位為字節(jié) -XX:MaxTenuringThreshold=7: 表示一個(gè)對(duì)象如果在Survivor區(qū)移動(dòng)了7次那下次MinorGC時(shí)就進(jìn)入老年代,。如果設(shè)置為0的話,則年輕代對(duì)象不經(jīng)過(guò)Survivor區(qū),,直接進(jìn)入年老代,,對(duì)于需要大量常駐內(nèi)存的應(yīng)用,這樣做可以提高效率。如果將此值設(shè)置為一個(gè)較大值,,則年輕代對(duì)象會(huì)在Survivor區(qū)進(jìn)行多次復(fù)制,,這樣可以增加對(duì)象在年輕代存活時(shí)間,增加對(duì)象在年輕代被垃圾回收的概率,,減少Full GC的頻率,,可以在某種程度上提高服務(wù)穩(wěn)定性。 -XX:+PrintTenuringDistribution:讓JVM在每次MinorGC后打印出當(dāng)前使用的Survivor中對(duì)象的年齡分布,。示例: Desired survivor size 75497472 bytes, new threshold 15 (max 15) - age 1: 19321624 bytes, 19321624 total - age 2: 79376 bytes, 19401000 total - age 3: 2904256 bytes, 22305256 total 第一行顯示Survivor容量及對(duì)象被移到老年代的年齡閾值,。 第二行起,每行顯示當(dāng)前Survivor中某個(gè)年齡下對(duì)象的大小及小于等于該年齡的對(duì)象大小總和,。因?yàn)槟壳癝urvivor空間中對(duì)象的大小22M小于期望Survivor空間的大小72M,,所以沒(méi)有對(duì)象會(huì)被移到老年代。 假設(shè)下一次MinorGC后的輸出結(jié)果為: Desired survivor size 75497472 bytes, new threshold 2 (max 15) - age 1: 68407384 bytes, 68407384 total - age 2: 12494576 bytes, 80901960 total - age 3: 79376 bytes, 80981336 total - age 4: 2904256 bytes, 83885592 total 上次MinorGC后還存活的對(duì)象在這次MinorGC年齡都增加了1,,可以看到上次年齡為2和3的對(duì)象(對(duì)應(yīng)在這次GC后的年齡為3和4)依然存在(大小未變),,而一部分上次對(duì)象年齡為1的對(duì)象在這次GC時(shí)被回收了。同時(shí)可以看到這次新增了約68M的新對(duì)象,。這次MinorGC后Survivor區(qū)域中對(duì)象總的大小為約83M,,大于了期望的Survivor空間的大小72M,因此它就把對(duì)象移到老年代的年齡的閾值調(diào)整為2,,在下次MinorGC時(shí)一部分對(duì)象就會(huì)被移到老年代了,。 相關(guān)的調(diào)整選項(xiàng)有: - -XX:InitialTenuringThreshold 表示對(duì)象被移到老年代的年齡閾值的初始值 - -XX:MaxTenuringThreshold 表示對(duì)象被移到老年代的年齡閾值的最大值 - -XX:TargetSurvivorRatio 表示MinorGC結(jié)束了Survivor區(qū)域中占用空間的期望比例。 這些參數(shù)的調(diào)節(jié)沒(méi)有統(tǒng)一的標(biāo)準(zhǔn),,但是有兩點(diǎn)可以借鑒: 2.5.4,、直接內(nèi)存 -XX:MaxDirectMemorySize:指定DirectMemory容量,,若未指定,則默認(rèn)與Java堆最大值一樣,。
每個(gè)進(jìn)程能使用的內(nèi)存大小受操作系統(tǒng)的限制,,在堆等的內(nèi)存大小不變時(shí),,配置的棧內(nèi)存越小,能開(kāi)啟的線程數(shù)越多,。
2.6,、OutofMemory相關(guān)的選項(xiàng)如果程序發(fā)生了OOM后,JVM可以配置一些選項(xiàng)來(lái)做些善后工作,,比如把內(nèi)存給dump下來(lái)以分析原因,,或者自動(dòng)采取一些別的動(dòng)作。
比如,,下面的命令可以使得在發(fā)生OOM的時(shí)候,,Heap被轉(zhuǎn)存到文件/tmp/heapdump.hprof,同時(shí)執(zhí)行Home目錄中的cleanup.sh文件: java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/heapdump.hprof -XX:OnOutOfMemoryError ="sh ~/cleanup.sh" MyApp
2.7,、收集器設(shè)置2.7.1,、吞吐量?jī)?yōu)先收集器的相關(guān)選項(xiàng) 衡量JVM垃圾收集器的兩個(gè)基本指標(biāo)是吞吐量和停頓時(shí)間。 吞吐量是指執(zhí)行用戶代碼的時(shí)間占總的時(shí)間的比例,,總的時(shí)間包括執(zhí)行用戶代碼的時(shí)間和垃圾回收占用的時(shí)間,。在垃圾回收的時(shí)候執(zhí)行用戶代碼的線程必須暫停,這會(huì)導(dǎo)致程序暫時(shí)失去響應(yīng),。停頓時(shí)間就是衡量垃圾回收時(shí)造成的用戶線程暫停的時(shí)間,。這兩個(gè)指標(biāo)在一定程度是相互矛盾的,不可能讓一個(gè)程序的吞吐量很高的同時(shí)停頓時(shí)間也短,,只能以優(yōu)先選擇一個(gè)目標(biāo)或者折中一下,。因此,不同的垃圾回收器會(huì)有不同的側(cè)重點(diǎn),。 在Hotspot JVM中,,側(cè)重于吞吐量的垃圾回收器是Parallel Scavenge和Parallel Old,它的相關(guān)選項(xiàng)如下:
此外,,如果機(jī)器只有一個(gè)核的話,采用并行回收器可能得不償失,,因?yàn)槎鄠€(gè)回收線程會(huì)爭(zhēng)搶CPU資源,,反而造成更大的消耗。這時(shí),,就最好采用串行回收器,,相關(guān)的參數(shù)是-XX:+UseSerialGC 2.7.2、CMS收集器 CMS收集器(ConcurrentMarkandSweep),,是一個(gè)關(guān)注系統(tǒng)停頓時(shí)間的收集器,。它的主要思想是把收集器分成了不同的階段,其中某些階段是可以用戶程序并行的,,從而減少了整體的系統(tǒng)停頓時(shí)間,。它主要分成了以下幾個(gè)階段: - 初始標(biāo)記 initial mark CMS雖然能減少系統(tǒng)的停頓時(shí)間,但是它也有其缺點(diǎn): 當(dāng)上面的任何一種情況發(fā)生的時(shí)候,,JVM就會(huì)觸發(fā)一次Full GC,,會(huì)導(dǎo)致JVM停頓較長(zhǎng)時(shí)間。 它的相關(guān)選項(xiàng)如下:
2.8,、GC日志相關(guān)的選項(xiàng)分析GC問(wèn)題不可避免地要查看GC日志,,下面是一些GC日志相關(guān)的選項(xiàng):
[GC 425355K->351685K(506816K), 0.2175300 secs] [Full GC 500561K->456058K(506816K), 0.6421920 secs] 其中以GC開(kāi)頭的行表示發(fā)生了一次Minor GC,,后面的數(shù)字表示收集前后Heap空間的占用量,圓括號(hào)里面表示Heap大小,,最后的數(shù)字表示用了多少時(shí)間,。比如:上面的例子中,表示在這次GC新生代空間占用從425355K降到了351685K,,總的新生代空間為506816K,,這次GC耗時(shí)0.22秒。
比如,以下是-XX:+PrintGCTimeStamps的輸出 0,185: [GC 66048K->53077K(251392K), 0,0977580 secs] 0,323: [GC 119125K->114661K(317440K), 0,1448850 secs] 0,603: [GC 246757K->243133K(375296K), 0,2860800 secs] 以下是兩個(gè)都打開(kāi)后的輸出: 2014-12-26T17:52:38.613-0800: 3.395: [GC 139776K->58339K(506816K), 0.1442900 secs]
需要注意的是:這些和GC日志相關(guān)的選項(xiàng)可以在JVM已經(jīng)啟動(dòng)后再開(kāi)啟,可以通過(guò)jinfo這個(gè)工具去設(shè)置,。具體可以參見(jiàn)jinfo的幫助文件,。這樣就可以在需要診斷問(wèn)題的時(shí)候再開(kāi)啟GC日志。
最后給一個(gè)示例: -Xmx3550m:設(shè)置JVM最大堆內(nèi)存為3550M,。 -Xms3550m:設(shè)置JVM初始堆內(nèi)存為3550M,。此值可以設(shè)置與-Xmx相同,以避免每次垃圾回收完成后JVM重新分配內(nèi)存,。 -Xss128k:設(shè)置每個(gè)線程的棧大小,。JDK5.0以后每個(gè)線程棧大小為1M,之前每個(gè)線程棧大小為256K,。應(yīng)當(dāng)根據(jù)應(yīng)用的線程所需內(nèi)存大小進(jìn)行調(diào)整,。在相同物理內(nèi)存下,減小這個(gè)值能生成更多的線程,。但是操作系統(tǒng)對(duì)一個(gè)進(jìn)程內(nèi)的線程數(shù)還是有限制的,,不能無(wú)限生成,經(jīng)驗(yàn)值在3000~5000左右,。需要注意的是:當(dāng)這個(gè)值被設(shè)置的較大(例如>2MB)時(shí)將會(huì)在很大程度上降低系統(tǒng)的性能,。 -Xmn2g:設(shè)置年輕代大小為2G。在整個(gè)堆內(nèi)存大小確定的情況下,,增大年輕代將會(huì)減小年老代,,反之亦然。此值關(guān)系到JVM垃圾回收,,對(duì)系統(tǒng)性能影響較大,,官方推薦配置為整個(gè)堆大小的3/8。 -XX:NewSize=1024m:設(shè)置年輕代初始值為1024M,。 -XX:MaxNewSize=1024m:設(shè)置年輕代最大值為1024M,。 -XX:PermSize=256m:設(shè)置持久代初始值為256M。 -XX:MaxPermSize=256m:設(shè)置持久代最大值為256M,。 -XX:NewRatio=4:設(shè)置年輕代(包括1個(gè)Eden和2個(gè)Survivor區(qū))與年老代的比值,。表示年輕代比年老代為1:4。 -XX:SurvivorRatio=4:設(shè)置年輕代中Eden區(qū)與Survivor區(qū)的比值,。表示2個(gè)Survivor區(qū)(JVM堆內(nèi)存年輕代中默認(rèn)有2個(gè)大小相等的Survivor區(qū))與1個(gè)Eden區(qū)的比值為2:4,,即1個(gè)Survivor區(qū)占整個(gè)年輕代大小的1/6。 -XX:MaxTenuringThreshold=7:表示一個(gè)對(duì)象如果在Survivor區(qū)(救助空間)移動(dòng)了7次還沒(méi)有被垃圾回收就進(jìn)入年老代,。如果設(shè)置為0的話,,則年輕代對(duì)象不經(jīng)過(guò)Survivor區(qū),直接進(jìn)入年老代,,對(duì)于需要大量常駐內(nèi)存的應(yīng)用,,這樣做可以提高效率。如果將此值設(shè)置為一個(gè)較大值,,則年輕代對(duì)象會(huì)在Survivor區(qū)進(jìn)行多次復(fù)制,,這樣可以增加對(duì)象在年輕代存活時(shí)間,增加對(duì)象在年輕代被垃圾回收的概率,,減少Full GC的頻率,,這樣做可以在某種程度上提高服務(wù)穩(wěn)定性。
3,、Java代碼獲取JVM相關(guān)參數(shù)可以借助java.lang.management.*:
代碼示例:
View Code
輸出:
View Code
4,、參考資料(轉(zhuǎn)載請(qǐng)注明出處,謝謝) |
|
來(lái)自: 關(guān)平藏書(shū) > 《JAVA》