java應用監測(2)-java命令的祕密
tags: java,troubleshooting,monitor
一句話概括:簡單的java啟動命令,原來藏著這麼多祕密,本文為你揭曉。
1 引言
剛開始學java的同學,一定都不會忘記安裝完jdk後,都會使用java -version
命令來檢測一下是否安裝成功,那還有沒有其它引數可以使用呢?平時開發和執行java應用時,經常看到一些-D
的引數(如使用maven時,package
時會使用-Dmaven.test.skip
),這些引數是用來做什麼的?還有經常說到調優,都會涉及到-Xms
和-Xmx
的設定,它是什麼意思呢?這些,基本都是在使用java
命令啟動應用時所使用的引數,它的引數有很多,特別涉及到應用調優和問題診斷時會經常使用,學習java的同學都應該瞭解一下。本文將對java命令的啟動引數進行詳細描述,著重講解常用的設定及用於除錯監測的設定。
2 java應用啟動
啟動java應用使用的是java
(class檔案)或java -jar
(jar或war包)命令,java命令其實就是生成一個JVM的例項,java應用則執行於此JVM例項中,JVM負責類載入,執行時區域堆疊分配等工作,當應用退出,JVM例項也會關閉。啟動多個java應用,也會啟動多個JVM例項,它們不會相互影響(但它們都共享同一系統的資源),這也是為什麼使用一個JDK,可以跑多個java應用的背後邏輯。使用java命令啟動應用所使用的引數,基本是用於JVM的,JVM例項通過呼叫某個初始類的main()方法來執行一個Java程式,此方法將作為該程式初始執行緒的起點,任何其他的執行緒都是由這個初始執行緒啟動的。在JVM內部有兩種執行緒:守護執行緒(如垃圾回收執行緒)和非守護執行緒(main
Thread
建立的執行緒),當該程式中所有的非守護執行緒都終止時,JVM例項將自動退出。
3 java應用啟動引數說明
java命令究竟有哪些引數可以用,這些引數分別有什麼作用,簡單的不帶引數使用java
或java -help
或java -?
,即可看到此命令的使用方法及引數描述,如下所示:
java
執行類檔案,java -jar
執行jar
或war
檔案。上面只是把引數簡要的列了出來,更詳細的引數說明,可參考官網的java
命令說明(https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html
)。使用java命令啟動應用所使用的引數,基本是用於JVM的,某種程度上也叫做JVM引數。總的來說,java啟動引數共分為三大類,分別是:
- 標準引數(-):相對穩定的引數,每個版本的JVM都可用。
- 非標準X引數(-X):預設jvm實現這些引數的功能,但是並不保證所有jvm實現都滿足,且不保證向後相容。
- XX引數(-XX):此類引數各個jvm實現會有所不同,將來可能會隨時取消。
下面將會對這些引數進行說明。
3.1 標準引數(-)
從前面使用java -?
可以看到,以-
開頭的引數,都屬於標準引數,我們常用的-help
,-version
,-classpath
,-Dproperty=value
等均屬於標準引數。引數詳細說明如下:
-d32及-d64 分別表示應用執行在32位或64位的環境中,使用Java HotSpot Server VM的預設使用的是server模式,而server模式預設使用的是-d64,因此在沒有使用此引數時,預設就是-d64。
-server 選擇 "server" VM,預設 VM 是 server,表示是在伺服器類計算機上執行。
-cp或-classpath <目錄和 zip/jar 檔案的類搜尋路徑>linux用":",windows用";"來分隔目錄,JAR 檔案和 ZIP 檔案列表,用於搜尋類檔案。
使用-classpath後jvm將不再使用CLASSPATH中的類搜尋路徑,如果-classpath和CLASSPATH都沒有設定,則jvm使用當前路徑(.)作為類搜尋路徑。
-D<名稱>=<值> 設定系統屬性,執行在此jvm之上的應用程式可用System.getProperty(“property”)得到value的值。
如果value中有空格,則需要用雙引號將該值括起來,如-Dfoo=”foo bar”。該引數通常用於設定系統級全域性變數值,如配置檔案路徑,以便該屬性在程式中任何地方都可訪問。
-verbose:[class|gc|jni] 啟用詳細輸出,一般在除錯和診斷時,都會把gc的詳細資訊輸出
-version 輸出產品版本並退出
-version:<值> 需要指定的版本才能執行
-showversion 輸出產品版本並繼續,即輸出版本後,繼續按java執行,這是跟-version的區別
-jre-restrict-search | -no-jre-restrict-search 在版本搜尋中包括/排除使用者專用 JRE
-? -help 輸出此幫助訊息
-X 輸出非標準選項的幫助
-ea或-enableassertions [:<packagename>...|:<classname>] 按指定的粒度啟用斷言,預設jvm關閉斷言機制
-da或-disableassertions [:<packagename>...|:<classname>] 禁用具有指定粒度的斷言
-esa | -enablesystemassertions 啟用系統斷言
-dsa | -disablesystemassertions 禁用系統斷言
-agentlib:<libname>[=<選項>] 載入本機代理庫 <libname>,例如 -agentlib:hprof
另請參閱 -agentlib:jdwp=help 和 -agentlib:hprof=help
-agentpath:<pathname>[=<選項>] 按完整路徑名載入本機代理庫
-javaagent:<jarpath>[=<選項>] 載入Java程式語言代理,請參閱 java.lang.instrument
-splash:<imagepath> 使用指定的影象顯示啟動螢幕,一般用於圖形程式設計。
複製程式碼
由上面描述可,可知道我們常用的-version
,-classpath
,-Dproperty=value
是用於做什麼的了。特別提一下-classpath
(以前遇到由於這個導致執行問題),jvm在載入類時,搜尋的路徑就是此路徑,而它在linux及windows使用的分隔符是不一樣的,linux用:
,windows用;
來分隔。
3.2 非標準X引數(-X)
使用命令java -X
,即可把非標準引數輸出,平時使用中,我們用得較多的就是-Xloggc
,-Xms<size>
,-Xmx<size>
,-Xss<size>
,-Xmn<size>
了,詳細說明如下所示:
-Xmixed 預設是mixed,使用它們來設定JVM的原生程式碼編譯模式
-Xint 表示解釋執行,所有的位元組碼將被直接執行,而不會編譯成本地碼
-Xcomp 表示第一次使用就編譯成原生程式碼。
-Xbatch 禁止後臺程式碼編譯,強制在前臺編譯,編譯完成之後才能進行程式碼執行,預設情況下,jvm在後臺進行編譯,若沒有編譯完成,則前臺執行程式碼時以解釋模式執行
-Xbootclasspath: 設定搜尋路徑以引導類和資源,讓jvm從指定路徑(可以是分號分隔的目錄、jar、或者zip)中載入bootclass,用來替換jdk的rt.jar
-Xbootclasspath/a: 附加在引導類路徑末尾
-Xbootclasspath/p: 置於引導類路徑之前,讓jvm優先於bootstrap預設路徑載入指定路徑的所有檔案
-Xcheck:jni 對JNI函式進行附加check;此時jvm將校驗傳遞給JNI函式引數的合法性,在原生程式碼中遇到非法資料時,jmv將報一個致命錯誤而終止;使用該引數後將造成效能下降,請慎用。
-Xfuture 讓jvm對類檔案執行嚴格的格式檢查(預設jvm不進行嚴格格式檢查),以符合類檔案格式規範,推薦開發人員使用該引數
-Xincgc 開啟增量gc(預設為關閉);這有助於減少長時間GC時應用程式出現的停頓;但由於可能和應用程式併發執行,所以會降低CPU對應用的處理能力
-Xloggc:file 與-verbose:gc功能類似,只是將每次GC事件的相關情況記錄到一個檔案中,檔案的位置最好在本地,以避免網路的潛在問題。若與verbose命令同時出現在命令列中,則以-Xloggc為準。
-Xms 指定jvm堆的初始大小,預設為實體記憶體的1/64,最小為1M;可以指定單位,比如k、m,若不指定,則預設為位元組。
-Xmx 指定jvm堆的最大值,預設為實體記憶體的1/4或者1G,最小為2M;單位與-Xms一致。
-Xss 設定單個執行緒棧的大小,一般預設為512k。
-Xmn 設定堆(heap)的年輕代的初始值及最大值,單位與-Xms一致,年輕代是儲存新物件的地址,也是GC發生得最頻繁的地方,若設定過小,則會容易觸發年輕代垃圾回收(minor gc),若設定過大,只觸發full gc,則佔用時間會很長,oracle建議是把年輕代設定在堆大小的四份之一到一半的。這命令同時設定了初始值和最大值,可以使用-XX:NewSize和-XX:MaxNewSiz來分別設定。
-XshowSettings 顯示所有設定並繼續
複製程式碼
上述引數中,-Xms<size>
,-Xmn<size>
都是我們效能優化中很重要的引數,-Xloggc
是在沒有專業跟蹤工具情況下排錯的好手。
3.3 XX引數(-XX)
此類引數非常豐富,包括高階執行時引數,高階JIT編譯引數,高階維護引數和高階GC引數,在官網可以看到它全部的引數(https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html
),各個版本jvm實現有可能會有所不同。其中按設定格式,主要分為兩類,一種是boolean
型別,主要用於功能開關,一種是key-value
型別,主要效能、除錯引數等設定,下面列舉一些主要使用的引數。
3.3.1 boolean型別
此類引數,格式:-XX:[+-]<name>
,作為功能開關,表示啟用或者禁用屬性。以下列舉一些:
-XX:+PrintFlagsFinal 輸出引數的最終值
-XX:+PrintFlagsInitial 輸出引數的預設值
-XX:-DisableExplicitGC 禁止呼叫System.gc();但jvm的gc仍然有效
-XX:+MaxFDLimit 最大化檔案描述符的數量限制
-XX:+ScavengeBeforeFullGC 新生代GC優先於Full GC執行
-XX:+UseGCOverheadLimit 在丟擲OOM之前限制jvm耗費在GC上的時間比例
-XX:-UseConcMarkSweepGC 對老生代採用併發標記交換演演算法進行GC
-XX:-UseParallelGC 啟用並行GC
-XX:-UseParallelOldGC 對Full GC啟用並行,當-XX:-UseParallelGC啟用時該項自動啟用
-XX:-UseSerialGC 啟用序列GC
-XX:+UseThreadPriorities 啟用本地執行緒優先順序
-XX:-UseG1GC 啟用G1的GC
複製程式碼
3.3.2 key-value型別
此類引數,格式:-XX:<name>=<value>
表示屬性name的值為value。在效能調優和除錯監測時,會經常用到。
- 效能調優
效能調優時,主要是對JVM的記憶體分配情況的調優,包括堆大小,年輕代大小,年輕年老代比例等等。
-XX:LargePageSizeInBytes=4m 設定用於Java堆的大頁面尺寸
-XX:MaxHeapFreeRatio=70 GC後java堆中空閒量佔的最大比例
-XX:MaxNewSize=size 新生成物件能佔用記憶體的最大值
-XX:MaxPermSize=64m 老生代物件能佔用記憶體的最大值
-XX:MinHeapFreeRatio=40 GC後java堆中空閒量佔的最小比例
-XX:NewRatio=2 新生代記憶體容量與老生代記憶體容量的比例
-XX:NewSize=2.125m 新生代物件生成時佔用記憶體的預設值
-XX:ReservedCodeCacheSize=32m 保留程式碼佔用的記憶體容量
-XX:ThreadStackSize=512 設定執行緒棧大小,若為0則使用系統預設值
-XX:+UseLargePages 使用大頁面記憶體
複製程式碼
- 除錯監測
在需要對應用進行監測,特別是觀察GC情況,OOM後檢查問題等。
-XX:-CITime 列印消耗在JIT編譯的時間
-XX:ErrorFile=./hs_err_pid<pid>.log 儲存錯誤日誌或者資料到檔案中
-XX:-ExtendedDTraceProbes 開啟solaris特有的dtrace探針
-XX:HeapDumpPath=./java_pid<pid>.hprof 指定匯出堆資訊時的路徑或檔名
-XX:-HeapDumpOnOutOfMemoryError 當首次遭遇OOM時匯出此時堆中相關資訊
-XX:OnError="<cmd args>;<cmd args>" 出現致命ERROR之後執行自定義命令
-XX:OnOutOfMemoryError="<cmd args>;<cmd args>" 當首次遭遇OOM時執行自定義命令
-XX:-PrintClassHistogram 遇到Ctrl-Break後列印類例項的柱狀資訊,與jmap -histo功能相同
-XX:-PrintConcurrentLocks 遇到Ctrl-Break後列印併發鎖的相關資訊,與jstack -l功能相同
-XX:-PrintCommandLineFlags 列印在命令列中出現過的標記
-XX:-PrintCompilation 當一個方法被編譯時列印相關資訊
-XX:-PrintGC 每次GC時列印相關資訊
-XX:-PrintGC Details 每次GC時列印詳細資訊
-XX:-PrintGCTimeStamps 列印每次GC的時間戳
-XX:-TraceClassLoading 跟蹤類的載入資訊
-XX:-TraceClassLoadingPreorder 跟蹤被引用到的所有類的載入資訊
-XX:-TraceClassResolution 跟蹤常量池
-XX:-TraceClassUnloading 跟蹤類的解除安裝資訊
-XX:-TraceLoaderConstraints 跟蹤類載入器約束的相關資訊
複製程式碼
4 常用java應用啟動引數
經過前面幾個章節的介紹,大家應該對java的啟動引數(JVM引數)有一定的瞭解,但引數太多了,不可能把所有引數都得記住,有需要時,建議大家看-help
或者看官網說明來查閱。很多時候,我們只需要記住幾個常用的即可。下面總結一下常用的JVM引數。
4.1 常用標準引數
-
-version
,場景:想檢視JDK版本,java -version
。 -
-D<名稱>=<值>
,場景:maven跳過單元測試,使用java -Dmaven.test.skip=true
, -
-cp或-classpath
,場景:設定需要載入的jar包位置,使用java -cp lib/test.jar com.test.TestMain
-
-verbose:gc
,場景:輸出GC詳細資訊
4.2 常用X引數
-
-Xms<size>
和-Xmx<size>
,場景:由於記憶體不足發生oom,調大堆大小,如設定為1G,可以java -Xms1024m -Xmx1024m
,通常為了避免頻繁發生GC,-Xms
和-Xmx
設定為一致。 -
-Xss<size>
,場景:執行緒運算元及區域性變數多,把執行緒棧的大小調大,可以java -Xss1024k
-
-Xmn<size>
,場景:年輕代大小設定為512m,可以java -Xmn512m
-
-Xloggc:file
,場景:將每次GC事件的相關情況記錄到一個檔案中以便於後續分析,可以java -Xloggc:logs/gc.log
4.3 常用XX引數
列印GC相關的內容,包括堆情況,GC詳情,GC時間,發生OOM時,生成快照,發生錯誤是記錄錯誤日誌等,如下:
-XX:+PrintHeapAtGC
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-XX:+PrintGCTimeStamps
-XX:+PrintTenuringDistribution
-XX:+PrintGCApplicationStoppedTime
-XX:+HeapDumpOnOutOfMemoryError
-
-XX:HeapDumpPath=logs/heapdump.hprof
,發生OOM時,dump出快照到檔案heapdump.hprof
中。 -
-XX:ErrorFile=logs/java_error_%p.log
,發生JVM錯誤時,把日誌輸出到java_error_%p.log
中。
以上引數均是使用度很高的引數,在使用java
命令啟動應用時,可以把這些引數加上,以便於後續調優與問題診斷。
5 總結
簡單的java啟動命令,使用起來原來這麼複雜,當然一般來說,只使用java
或java -jar
來按預設值啟動應用,也不會有太大問題。只是涉及到調優、監測、診斷時,瞭解這些引數,無疑是高階程式設計師必要的技能。希望通過本文,大家對java
命令及引數可以做到心中有數。
參考資料
-
JDK工具參考檔案:
https://docs.oracle.com/javase/8/docs/technotes/tools/unix
相關閱讀
- 《java應用監測(1)-java程式設計師應該知道的應用監測技術》:
https://juejin.im/post/5d5fde94f265da03d42fae8b