溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

怎么理解JVM啟動(dòng)參數(shù)

發(fā)布時(shí)間:2021-10-23 15:43:17 來源:億速云 閱讀:229 作者:柒染 欄目:大數(shù)據(jù)

怎么理解JVM啟動(dòng)參數(shù),針對這個(gè)問題,這篇文章詳細(xì)介紹了相對應(yīng)的分析和解答,希望可以幫助更多想解決這個(gè)問題的小伙伴找到更簡單易行的方法。

因?yàn)镠otspot JDK提供的參數(shù)默認(rèn)值,在小版本之間不斷變化,參數(shù)之間也會(huì)互相影響。而且,服務(wù)器配置不同,都可能影響最后的效果。所以千萬不要迷信網(wǎng)上的某篇文章(包括這篇)里面的參數(shù)配置,一切的配置都需要自己親身測試一番才能用。

針對于JVM參數(shù)默認(rèn)值不斷變化,可以使用-XX:+PrintFlagsFinal打印當(dāng)前環(huán)境JVM參數(shù)默認(rèn)值,比如:java -XX:PrintFlagsFinal -version,也可以用java [生產(chǎn)環(huán)境參數(shù)] -XX:+PrintFlagsFinal –version | grep [待查證的參數(shù)]查看具體的參數(shù)數(shù)據(jù)。

這里是一個(gè)8G服務(wù)器的參數(shù),JDK版本信息如下:

java version "1.8.0_73"
Java(TM) SE Runtime Environment (build 1.8.0_73-b02)
Java HotSpot(TM) 64-Bit Server VM (build 25.73-b02, mixed mode)

堆設(shè)置

堆內(nèi)存設(shè)置應(yīng)該算是一個(gè)Java程序猿的基本素養(yǎng),最少也得修改過Xms、Xmx、Xmn這三個(gè)參數(shù)了。但是一個(gè)2G堆大小的JVM,可能總共占用多少內(nèi)存的?

    堆內(nèi)存 + 線程數(shù) * 線程棧 + 永久代 + 二進(jìn)制代碼 + 堆外內(nèi)存

    2G + 1000 * 1M + 256M + 48/240M + (~2G) = 5.5G (3.5G)
    - 堆內(nèi)存: 存儲(chǔ)Java對象,默認(rèn)為物理內(nèi)存的1/64
    - 線程棧: 存儲(chǔ)局部變量(原子類型,引用)及其他,默認(rèn)為1M
    - 永久代: 存儲(chǔ)類定義及常量池,注意JDK7/8的區(qū)別
    - 二進(jìn)制代碼:JDK7與8,打開多層編譯時(shí)的默認(rèn)值不一樣,從48到240M
    - 堆外內(nèi)存: 被Netty,堆外緩存等使用,默認(rèn)最大值約為堆內(nèi)存大小

也就是說,堆內(nèi)存設(shè)置為2G,那一個(gè)有1000個(gè)線程的JVM可能需要占5.5G,在考慮系統(tǒng)占用、IO占用等等各種情況,一臺(tái)8G的服務(wù)器,也就啟動(dòng)一個(gè)服務(wù)了。當(dāng)然,如果線程數(shù)少、并發(fā)不高、壓力不大,還是可以啟動(dòng)多個(gè),而且也可以把堆內(nèi)存降低。

    -Xms2g 與 -Xmx2g:堆內(nèi)存大小,第一個(gè)是最小堆內(nèi)存,第二個(gè)是最大堆內(nèi)存,比較合適的數(shù)值是2-4g,再大就得考慮GC時(shí)間
    -Xmn1g 或 (-XX:NewSize=1g 和 -XX:MaxNewSize=1g) 或 -XX:NewRatio=1:設(shè)置新生代大小,JDK默認(rèn)新生代占堆內(nèi)存大小的1/3,也就是-XX:NewRatio=2。這里是設(shè)置的1g,也就是-XX:NewRatio=1。可以根據(jù)自己的需要設(shè)置。
    -XX:MetaspaceSize=128m 和 -XX:MaxMetaspaceSize=512m,JDK8的永生代幾乎可用完機(jī)器的所有內(nèi)存,為了保護(hù)服務(wù)器不會(huì)因?yàn)閮?nèi)存占用過大無法連接,需要設(shè)置一個(gè)128M的初始值,512M的最大值保護(hù)一下。
    -XX:SurvivorRatio:新生代中每個(gè)存活區(qū)的大小,默認(rèn)為8,即1/10的新生代, 1/(SurvivorRatio+2),有人喜歡設(shè)小點(diǎn)省點(diǎn)給新生代,但要避免太小使得存活區(qū)放不下臨時(shí)對象而要晉升到老生代,還是從GC Log里看實(shí)際情況了。
    -Xss256k:在堆之外,線程占用棧內(nèi)存,默認(rèn)每條線程為1M。存放方法調(diào)用出參入?yún)⒌臈?、局部變量、?biāo)量替換后的局部變量等,有人喜歡設(shè)小點(diǎn)節(jié)約內(nèi)存開更多線程。但反正內(nèi)存夠也就不必要設(shè)小,有人喜歡再設(shè)大點(diǎn),特別是有JSON解析之類的遞歸調(diào)用時(shí)不能設(shè)太小。
    -XX:MaxDirectMemorySize:堆外內(nèi)存/直接內(nèi)存的大小,默認(rèn)為堆內(nèi)存減去一個(gè)Survivor區(qū)的大小。
    -XX:ReservedCodeCacheSize:JIT編譯后二進(jìn)制代碼的存放區(qū),滿了之后就不再編譯。默認(rèn)開多層編譯240M,可以在JMX里看看CodeCache的大小。

GC設(shè)置

目前比較主流的GC是CMS和G1,有大神建議以8G為界。(據(jù)說JDK 9默認(rèn)的是G1)。因?yàn)閼?yīng)用設(shè)置的內(nèi)存都比較小,所以選擇CMS收集器。下面的參數(shù)也是針對CMS收集器的,等之后如果有需要,再補(bǔ)充G1收集器的參數(shù)。
CMS設(shè)置

    -XX:+UseConcMarkSweepGC:啟用CMS垃圾收集器
    -XX:CMSInitiatingOccupancyFraction=80 與 -XX:+UseCMSInitiatingOccupancyOnly:兩個(gè)參數(shù)需要配合使用,否則第一個(gè)參數(shù)的75只是一個(gè)參考值,JVM會(huì)重新計(jì)算GC的時(shí)間。
    -XX:MaxTenuringThreshold=15:對象在Survivor區(qū)熬過多少次Young GC后晉升到年老代,默認(rèn)是15。Young GC是最大的應(yīng)用停頓來源,而新生代里GC后存活對象的多少又直接影響停頓的時(shí)間,所以如果清楚Young GC的執(zhí)行頻率和應(yīng)用里大部分臨時(shí)對象的最長生命周期,可以把它設(shè)的更短一點(diǎn),讓其實(shí)不是臨時(shí)對象的新生代長期對象趕緊晉升到年老代。
    -XX:-DisableExplicitGC:允許使用System.gc()主動(dòng)調(diào)用GC。這里需要說明下,有的JVM優(yōu)化建議是設(shè)置-XX:-DisableExplicitGC,關(guān)閉手動(dòng)調(diào)用System.gc()。這是應(yīng)為System.gc()是觸發(fā)Full GC,頻繁的Full GC會(huì)嚴(yán)重影響性能。但是很多NIO框架,比如Netty,會(huì)使用堆外內(nèi)存,如果沒有Full GC的話,堆外內(nèi)存就無法回收。如果不主動(dòng)調(diào)用System.gc(),就需要等到JVM自己觸發(fā)Full GC,這個(gè)時(shí)候,就可能引起長時(shí)間的停頓(STW),而且機(jī)器負(fù)載也會(huì)升高。所以不能夠完全禁止System.gc(),又得縮短Full GC的時(shí)間,那就使用-XX:+ExplicitGCInvokesConcurrent或-XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses選項(xiàng),使用CMS收集器來觸發(fā)Full GC。這兩個(gè)選項(xiàng)需要配合-XX:+UseConcMarkSweepGC使用。
    -XX:+ExplicitGCInvokesConcurrent:使用System.gc()時(shí)觸發(fā)CMS GC,而不是Full GC。默認(rèn)是不開啟的,只有使用-XX:+UseConcMarkSweepGC選項(xiàng)的時(shí)候才能開啟這個(gè)選項(xiàng)。
    -XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses:使用System.gc()時(shí),永久代也被包括進(jìn)CMS范圍內(nèi)。只有使用-XX:+UseConcMarkSweepGC選項(xiàng)的時(shí)候才能開啟這個(gè)選項(xiàng)。
    -XX:+ParallelRefProcEnabled:默認(rèn)為false,并行的處理Reference對象,如WeakReference,除非在GC log里出現(xiàn)Reference處理時(shí)間較長的日志,否則效果不會(huì)很明顯。
    -XX:+ScavengeBeforeFullGC:在Full GC執(zhí)行前先執(zhí)行一次Young GC。
    -XX:+UseGCOverheadLimit: 限制GC的運(yùn)行時(shí)間。如果GC耗時(shí)過長,就拋OOM。
    -XX:+UseParallelGC:設(shè)置并行垃圾收集器
    -XX:+UseParallelOldGC:設(shè)置老年代使用并行垃圾收集器
    -XX:-UseSerialGC:關(guān)閉串行垃圾收集器
    -XX:+CMSParallelInitialMarkEnabled 和 -XX:+CMSParallelRemarkEnabled:降低標(biāo)記停頓
    -XX:+CMSScavengeBeforeRemark:默認(rèn)為關(guān)閉,在CMS remark前,先執(zhí)行一次minor GC將新生代清掉,這樣從老生代的對象引用到的新生代對象的個(gè)數(shù)就少了,停止全世界的CMS remark階段就短一些。如果看到GC日志里remark階段的時(shí)間超長,可以打開此項(xiàng)看看有沒有效果,否則還是不要打開了,白白多了次YGC。
    -XX:CMSWaitDuration=10000:設(shè)置垃圾收集的最大時(shí)間間隔,默認(rèn)是2000。
    -XX:+CMSClassUnloadingEnabled:在CMS中清理永久代中的過期的Class而不等到Full GC,JDK7默認(rèn)關(guān)閉而JDK8打開。看自己情況,比如有沒有運(yùn)行動(dòng)態(tài)語言腳本如Groovy產(chǎn)生大量的臨時(shí)類。它會(huì)增加CMS remark的暫停時(shí)間,所以如果新類加載并不頻繁,這個(gè)參數(shù)還是不開的好。

GC日志

GC過程可以通過GC日志來提供優(yōu)化依據(jù)。

    -XX:+PrintGCDetails:啟用gc日志打印功能
    -Xloggc:/path/to/gc.log:指定gc日志位置
    -XX:+PrintHeapAtGC:打印GC前后的詳細(xì)堆棧信息
    -XX:+PrintGCDateStamps:打印可讀的日期而不是時(shí)間戳
    -XX:+PrintGCApplicationStoppedTime:打印所有引起JVM停頓時(shí)間,如果真的發(fā)現(xiàn)了一些不知什么的停頓,再臨時(shí)加上-XX:+PrintSafepointStatistics -XX: PrintSafepointStatisticsCount=1找原因。
    -XX:+PrintGCApplicationConcurrentTime:打印JVM在兩次停頓之間正常運(yùn)行時(shí)間,與-XX:+PrintGCApplicationStoppedTime一起使用效果更佳。
    -XX:+PrintTenuringDistribution:查看每次minor GC后新的存活周期的閾值
    -XX:+UseGCLogFileRotation 與 -XX:NumberOfGCLogFiles=10 與 -XX:GCLogFileSize=10M:GC日志在重啟之后會(huì)清空,但是如果一個(gè)應(yīng)用長時(shí)間不重啟,那GC日志會(huì)增加,所以添加這3個(gè)參數(shù),是GC日志滾動(dòng)寫入文件,但是如果重啟,可能名字會(huì)出現(xiàn)混亂。
    -XX:PrintFLSStatistics=1:打印每次GC前后內(nèi)存碎片的統(tǒng)計(jì)信息

其他參數(shù)設(shè)置

    -ea:啟用斷言,這個(gè)沒有什么好說的,可以選擇啟用,或這選擇不啟用,沒有什么大的差異。完全根據(jù)自己的系統(tǒng)進(jìn)行處理。
    -XX:+UseThreadPriorities:啟用線程優(yōu)先級,主要是因?yàn)槲覀兛梢越o予周期性任務(wù)更低的優(yōu)先級,以避免干擾客戶端工作。在我當(dāng)前的環(huán)境中,是默認(rèn)啟用的。
    -XX:ThreadPriorityPolicy=42:允許降低線程優(yōu)先級
    -XX:+HeapDumpOnOutOfMemoryError:發(fā)生內(nèi)存溢出是進(jìn)行heap-dump
    -XX:HeapDumpPath=/path/to/java_pid.hprof:這個(gè)參數(shù)與-XX:+HeapDumpOnOutOfMemoryError共同作用,設(shè)置heap-dump時(shí)內(nèi)容輸出文件。
    -XX:ErrorFile=/path/to/hs_err_pid.log:指定致命錯(cuò)誤日志位置。一般在JVM發(fā)生致命錯(cuò)誤時(shí)會(huì)輸出類似hs_err_pid.log的文件,默認(rèn)是在工作目錄中(如果沒有權(quán)限,會(huì)嘗試在/tmp中創(chuàng)建),不過還是自己指定位置更好一些,便于收集和查找,避免丟失。
    -XX:StringTableSize=1000003:指定字符串常量池大小,默認(rèn)值是60013。對Java稍微有點(diǎn)常識的應(yīng)該知道,字符串是常量,創(chuàng)建之后就不可修改了,這些常量所在的地方叫做字符串常量池。如果自己系統(tǒng)中有很多字符串的操作,且這些字符串值比較固定,在允許的情況下,可以適當(dāng)調(diào)大一些池子大小。
    -XX:+AlwaysPreTouch:在啟動(dòng)時(shí)把所有參數(shù)定義的內(nèi)存全部捋一遍。使用這個(gè)參數(shù)可能會(huì)使啟動(dòng)變慢,但是在后面內(nèi)存使用過程中會(huì)更快??梢员WC內(nèi)存頁面連續(xù)分配,新生代晉升時(shí)不會(huì)因?yàn)樯暾垉?nèi)存頁面使GC停頓加長。通常只有在內(nèi)存大于32G的時(shí)候才會(huì)有感覺。
    -XX:-UseBiasedLocking:禁用偏向鎖(在存在大量鎖對象的創(chuàng)建且高度并發(fā)的環(huán)境下(即非多線程高并發(fā)應(yīng)用)禁用偏向鎖能夠帶來一定的性能優(yōu)化)
    -XX:AutoBoxCacheMax=20000:增加數(shù)字對象自動(dòng)裝箱的范圍,JDK默認(rèn)-128~127的int和long,超出范圍就會(huì)即時(shí)創(chuàng)建對象,所以,增加范圍可以提高性能,但是也是需要測試。
    -XX:-OmitStackTraceInFastThrow:不忽略重復(fù)異常的棧,這是JDK的優(yōu)化,大量重復(fù)的JDK異常不再打印其StackTrace。但是如果系統(tǒng)是長時(shí)間不重啟的系統(tǒng),在同一個(gè)地方跑了N多次異常,結(jié)果就被JDK忽略了,那豈不是查看日志的時(shí)候就看不到具體的StackTrace,那還怎么調(diào)試,所以還是關(guān)了的好。
    -XX:+PerfDisableSharedMem:啟用標(biāo)準(zhǔn)內(nèi)存使用。JVM控制分為標(biāo)準(zhǔn)或共享內(nèi)存,區(qū)別在于一個(gè)是在JVM內(nèi)存中,一個(gè)是生成/tmp/hsperfdata_{userid}/{pid}文件,存儲(chǔ)統(tǒng)計(jì)數(shù)據(jù),通過mmap映射到內(nèi)存中,別的進(jìn)程可以通過文件訪問內(nèi)容。通過這個(gè)參數(shù),可以禁止JVM寫在文件中寫統(tǒng)計(jì)數(shù)據(jù),代價(jià)就是jps、jstat這些命令用不了了,只能通過jmx獲取數(shù)據(jù)。但是在問題排查是,jps、jstat這些小工具是很好用的,比jmx這種很重的東西好用很多,所以需要自己取舍。這里有個(gè)GC停頓的例子。
    -Djava.net.preferIPv4Stack=true:這個(gè)參數(shù)是屬于網(wǎng)絡(luò)問題的一個(gè)參數(shù),可以根據(jù)需要設(shè)置。在某些開啟ipv6的機(jī)器中,通過InetAddress.getLocalHost().getHostName()可以獲取完整的機(jī)器名,但是在ipv4的機(jī)器中,可能通過這個(gè)方法獲取的機(jī)器名不完整,可以通過這個(gè)參數(shù)來獲取完整機(jī)器名。

大神給出的例子

下面貼上大神給出的例子,可以參考使用,不過還是建議在自己的環(huán)境中有針對的驗(yàn)證之后再使用,畢竟大神的環(huán)境和自己的環(huán)境還是不同。
性能相關(guān)

-XX:-UseBiasedLocking -XX:-UseCounterDecay -XX:AutoBoxCacheMax=20000
-XX:+PerfDisableSharedMem(可選) -XX:+AlwaysPreTouch -Djava.security.egd=file:/dev/./urandom
內(nèi)存大小相關(guān)(JDK7)

-Xms4096m -Xmx4096m -Xmn2048m -XX:MaxDirectMemorySize=4096m
-XX:PermSize=128m -XX:MaxPermSize=512m -XX:ReservedCodeCacheSize=240M

    如果使用jdk8,就把-XX:PermSize=128m -XX:MaxPermSize=512m換成-XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m,正如前面所說的,這兩套參數(shù)是為了保證安全的,建議還是加上。

CMS GC相關(guān)

-XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=75
-XX:+UseCMSInitiatingOccupancyOnly -XX:MaxTenuringThreshold=6
-XX:+ExplicitGCInvokesConcurrent -XX:+ParallelRefProcEnabled
GC日志相關(guān)

-Xloggc:/dev/shm/app-gc.log -XX:+PrintGCApplicationStoppedTime
-XX:+PrintGCDateStamps -XX:+PrintGCDetails
異常日志相關(guān)

-XX:-OmitStackTraceInFastThrow -XX:ErrorFile=${LOGDIR}/hs_err_%p.log
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${LOGDIR}/
JMX相關(guān)

-Dcom.sun.management.jmxremote.port=${JMX_PORT} -Dcom.sun.management.jmxremote
-Djava.rmi.server.hostname=127.0.0.1 -Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
參考文章

    Java性能優(yōu)化指南1.8版,及唯品會(huì)的實(shí)戰(zhàn)
    Java中的逃逸分析和TLAB以及Java對象分配
    The Four Month Bug: JVM statistics cause garbage collection pauses
 

========================================================

Cassandra,在Linux系統(tǒng)中,默認(rèn)的JVM啟動(dòng)參數(shù)

-ea
-Xms4096MB
-Xmx4096MB
-Xss128K
-XX:+UseThreadPriorities 
-XX:ThreadPriorityPolicy=42
-XX:+HeapDumpOnOutOfMemoryError
-XX:+UseParNewGC
-XX:+UseConcMarkSweepGC
-XX:+CMSParallelRemarkEnabled
-XX:SurvivorRatio=8
-XX:MaxTenuringThreshold=1
-XX:CMSInitiatingOccupancyFraction=75
-XX:+UseCMSInitiatingOccupancyOnly

-ea 從JDK1.4開始,支持?jǐn)嘌詸C(jī)制,可以用于診斷運(yùn)行時(shí)問題。-ea用來啟動(dòng)JVM的斷言機(jī)制,如果不加packagename和classname,默認(rèn)運(yùn)行所有包和類中的斷言。如果希望進(jìn)行運(yùn)行某些包和類的斷言,可以類似 -ea:com.foo.util進(jìn)行設(shè)置。

-XX:+UseThreadPriorities  開啟JAVA線程優(yōu)先級的功能

-XX:ThreadPriorityPolicy JAVA線程優(yōu)先級的側(cè)臉

-XX:+HeapDumpOnOutOfMemoryError 在JVM內(nèi)存不足而引發(fā)程序崩潰時(shí),講內(nèi)存中的數(shù)據(jù)導(dǎo)出

-Xss128K 設(shè)置線程棧的大小,默認(rèn)單位為字節(jié),也可以用KB或MB來設(shè)置。通常操作系統(tǒng)分配給線程棧的默認(rèn)大小為1MB。另外,也可以在JAVA CODE中創(chuàng)建線程對象時(shí)設(shè)置棧的大小,Thread( TheadGroup group, Runnable target, String name, long stackSize)

-XX:+UseParNewGC 縮短JVM GC執(zhí)行minor收集的時(shí)間

-XX:+UseConcMarkSweepGC 縮短JVM GC執(zhí)行major收集的時(shí)間

-XX:+CMSParallelRemarkEnabled 縮短JVM GC執(zhí)行remark操作的中斷時(shí)間

-XX:SurvivorRatio 設(shè)置young generation 在 survivor spaces中所占用的大小比例

-XX:MaxTenuringThreshold 表示一個(gè)對象如果在survivor spaces移動(dòng)多少次還沒有被回收就放入老年代

-XX:CMSInitiatingOccupancyFraction 表示老年代占到約百分之多少的時(shí)候開始執(zhí)行CMS操作

-XX:+UseCMSInitiatingOccupancyOnly 這個(gè)參數(shù)讓JVM只使用CMSInitiatingOccupancyFraction 中定義的值而不用在運(yùn)行中計(jì)算

關(guān)于怎么理解JVM啟動(dòng)參數(shù)問題的解答就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注億速云行業(yè)資訊頻道了解更多相關(guān)知識。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

jvm
AI