最近在做 Java8 到 Java17 的遷移工作,前期做了一些準(zhǔn)備,但是在升級(jí)過(guò)程還是有些問(wèn)題,太emo了,一些信息記錄如下,分為幾個(gè)部分:
- 編譯相關(guān)
- 參數(shù)遷移相關(guān)
- 運(yùn)行相關(guān)
前人栽樹(shù)后人乘涼,有需要升級(jí)的可以參考一下,避免踩坑。。。
編譯相關(guān)
JEP 320
在 Java11 中引入了一個(gè)提案 JEP 320: Remove the Java EE and CORBA Modules (openjdk.org/jeps/320) 提案,移除了 Java EE and CORBA 的模塊,如果項(xiàng)目中用到需要手動(dòng)引入。比如代碼中用到了 javax.annotation.*
下的包:
publicabstractclassFridayAgent
@PreDestroy
publicvoiddestroy(){
agentClient.close();
}
}
在編譯時(shí)會(huì)找不到相關(guān)的類。這是因?yàn)?Java EE 已經(jīng)在 Java 9
中被標(biāo)記為 deprecated,Java 11 中被正式移除,可以手動(dòng)引入 javax 的包:
javax.annotation
javax.annotation-api
1.3.2
使用了 sun.misc.* 下的包
比如 sun.misc.BASE64Encoder,這個(gè)簡(jiǎn)單,替換一下工具類即可。
[ERROR]symbol:classBASE64Encoder
[ERROR]location:packagesun.misc
netty 低版本使用了 sun.misc.*,編譯錯(cuò)誤信息如下
Causedby:java.lang.NoClassDefFoundError:Couldnotinitializeclassio.netty.util.internal.PlatformDependent0
atio.netty.util.internal.PlatformDependent.getSystemClassLoader(PlatformDependent.java:694)~[netty-all-4.0.42.Final.jar!/:4.0.42.Final]
對(duì)應(yīng)的源碼如下:
/**
*The{@linkPlatformDependent}operationswhichrequiresaccessto{@codesun.misc.*}.
*/
finalclassPlatformDependent0{
}
https://github.com/netty/netty/issues/6855
lombok 使用了 com.sun.tools.javac.* 下的包
錯(cuò)誤信息如下:
Failed to execute goal org.apache.maven.plugins3.2:compile (default-compile) on project encloud-common: Fatal error compiling: java.lang.ExceptionInInitializerError: Unable to make field private com.sun.tools.javac.processing.JavacProcessingEnvironment$DiscoveredProcessors com.sun.tools.javac.processing.JavacProcessingEnvironment.discoveredProcs accessible: module jdk.compiler does not "opens com.sun.tools.javac.processing" to unnamed module
如果你的項(xiàng)目中使用 lombok,而且是低版本的話,就會(huì)出現(xiàn),lombok 的原理是在編譯期做一些手腳,用到了 com.sun.tools.javac
下的文件,升級(jí)到最新版可以解決。ps,個(gè)人很不喜歡 lombok, 調(diào)試的時(shí)候代碼和 class 對(duì)不上真的很惡心。
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.24version>
dependency>
kotlin 版本限制
我們后端在很多年前就 all-in Kotlin,Kotlin 的升級(jí)也是我們的重中之重。
[ERROR] Failed to execute goal org.jetbrains.kotlin1.2.71:compile (compile) on project encloud-core: Compilation failure [ERROR] Unknown JVM target version: 17 [ERROR] Supported versions: 1.6, 1.8
Kotlin 在 1.6.0 版本開(kāi)始支持 Java17 的字節(jié)碼,低于 1.6.0 的編譯會(huì)直接報(bào)錯(cuò)
廢棄依賴分析
可以用 jdeps --jdk-internals --multi-release 17 --class-path . encloud-api.jar
來(lái)做項(xiàng)目的依賴分析

這樣你就可以知道哪些庫(kù)需要做升級(jí)了。
基于 Spring Boot + MyBatis Plus + Vue & Element 實(shí)現(xiàn)的后臺(tái)管理系統(tǒng) + 用戶小程序,支持 RBAC 動(dòng)態(tài)權(quán)限、多租戶、數(shù)據(jù)權(quán)限、工作流、三方登錄、支付、短信、商城等功能
- 項(xiàng)目地址:https://gitee.com/zhijiantianya/ruoyi-vue-pro
- 視頻教程:https://doc.iocoder.cn/video/
參數(shù)遷移
什么是 Unified Logging
在 Java 領(lǐng)域,有廣為人知的日志框架,slf4j、log4j 等,這些框架提供了統(tǒng)一的編程接口,讓用戶可以通過(guò)簡(jiǎn)單的配置實(shí)現(xiàn)日志輸出的個(gè)性化配置,比如日志 tag、級(jí)別(info、debug 等)、上下文(線程 id、行號(hào)、時(shí)間等),在 JVM 內(nèi)部之前一直缺乏這樣的規(guī)范,于是出來(lái)了 Unified Logging,實(shí)現(xiàn)了日志格式的大一統(tǒng),這就是我們接下來(lái)要介紹的重點(diǎn) Unified Logging
。
我們接觸最多的是 gc 的日志,在 java8 中,我們配置 gc 日志的參數(shù)是 -Xloggc:/tmp/gc.log
。在 JVM 中除了 GC,還有大量的其它相關(guān)的日志,比如線程、os 等,在新的 Unified Logging 日志中,日志輸出的方式變更為了 java -Xlog:xxx
,GC 不再特殊只是做為日志的一種存在形式。
java-Xlog-version
輸出結(jié)果如下:

可以看到日志輸出里,不僅有 GC 相關(guān)的日志,還有 os 線程相關(guān)的信息。事實(shí)上 java 的日志的生產(chǎn)者有非常多部分,比如 thread、class load、unload、safepoint、cds 等。

歸根到底,日志打印,需要回答清楚三個(gè)問(wèn)題:
- what:要輸出什么信息(tag),以什么日志級(jí)別輸出(level)
- where:輸出到哪里(console 還是 file)
- decorators:日志如何
輸出什么信息(selectors)
首先來(lái)看 what 的部分,如何指定要輸出哪些信息,這個(gè)在 JVM 內(nèi)部被稱之為 selectors。
JVM 采用的是
的形式來(lái)表示 selectors,默認(rèn)情況下,tag 為all
,表示所有的 tag,level 為 INFO
,java -Xlog -version
等價(jià)于下面的形式
java-Xlog:all=info-version
如果我們想輸出tag 為 gc,日志級(jí)別為 debug 的日志,可以用 java -Xlog:gc=debug
的形式:
$java-Xlog:gc=debug-version
[0.023s][info][gc]UsingG1
[0.023s][debug][gc]ConcGCThreads:3offset22
[0.023s][debug][gc]ParallelGCThreads:10
[0.024s][debug][gc]Initializemarkstackwith4096chunks,maximum524288
這樣就輸出了 tag 為 gc,級(jí)別為 debug 的日志信息。
不過(guò)這里有一個(gè)比較坑的點(diǎn)是,這里的 tag 匹配規(guī)則是精確匹配,如果某條日志的 tag 是 gc,metaspace
,通過(guò)上面的規(guī)則是匹配不到的,我們可以手動(dòng)指定的方式來(lái)輸出。
$java-Xlog:gc+metaspace-version
[0.022s][info][gc,metaspace]CDSarchive(s)mappedat:...size12443648.
[0.022s][info][gc,metaspace]Compressedclassspacemappedat:reservedsize:...
[0.022s][info][gc,metaspace]Narrowklassbase:...,Narrow
klassshift:0,Narrowklassrange:0x100000000
這里的 selector 也是可以進(jìn)行組合的,不同的 selector 之間用逗號(hào)分隔即可。比如同時(shí)輸出 gc
和 gc+metaspace
這兩類 tag 的日志,就可以這么寫(xiě):
$java-Xlog:gc=debug,gc+metaspace-version
[0.020s][info][gc]UsingG1
[0.020s][debug][gc]ConcGCThreads:3offset22
[0.020s][debug][gc]ParallelGCThreads:10
[0.020s][debug][gc]Initializemarkstackwith4096chunks,maximum524288
[0.022s][info][gc,metaspace]CDSarchive(s)mappedat:
[0.022s][info][gc,metaspace]Compressedclassspacemappedat:
[0.022s][info][gc,metaspace]Narrowklassbase:0x0000000800000000
當(dāng)然這么搞是很麻煩的,JVM 提供了通配符 *
來(lái)解決精確匹配的問(wèn)題,比如我們想要所有 tag 為 gc 的日志,可以這么寫(xiě):
$java-Xlog:gc*=debug-version
[0.024s][debug][gc,heap]Minimumheap8388608
[0.024s][info][gc]UsingG1
[0.024s][debug][gc,heap,coops]Heapaddress:0x0000000707400000
[0.024s][debug][gc]ConcGCThreads:3offset22
[0.024s][debug][gc]ParallelGCThreads:10
[0.024s][debug][gc]Initializemarkstackwith4096chunks
[0.024s][debug][gc,ergo,heap]Expandtheheap.requestedexpansionamount:
[0.025s][debug][gc,heap,region]Activateregions[0,125)[0.025s][debug][gc,ihop]Targetoccupancyupdate:old:0B,new:262144000B
[0.025s][debug][gc,ergo,refine]InitialRefinementZones:green:2560
[0.026s][debug][gc,task]G1ServiceThread
[0.026s][debug][gc,task]G1ServiceThread(PeriodicGCTask)(register)
[0.026s][info][gc,init]Version:17.0.3+7(release)
...
如果只想要 INFO 級(jí)別的日志,則可以省略 level 的設(shè)置,使用 java -Xlog:gc* -version
即可。
如果想知道有哪些個(gè)性化的 tag 可以選擇,可以用 java -Xlog:help
來(lái)找到所有可用的 tag。
階段性小結(jié)

第二部分:輸出到哪里(output)
默認(rèn)情況下,日志會(huì)輸出到 stdout,jvm 支持以下三種輸出方式:
- stdout
- stderr
- file
一般而言我們會(huì)把日志輸出到文件中,方便后續(xù)進(jìn)一步分析
-Xlog:all=debug:file=/path_to_logs/app.log
還可以指定日志切割的大小和方式
-Xlogfile=/path_to_logs/app.log:filesize=104857600,filecount=5
第三部分:日志 decorators
每條日志除了正常的信息以外,還有不少日志相關(guān)的上下文信息,在 jvm 中被稱為 decorators
,有下面這些可選項(xiàng)。

比如可以用 java -Xlog:all=debuglevel,tags,time,uptime,pid -version
選項(xiàng)來(lái)打印日志。
[2022-06-15T1901.529+0800][0.001s][5235][info][os,thread]Threadattached
[2022-06-15T1901.529+0800][0.001s][5235][debug][os,thread]Thread5237stack...
[2022-06-15T1901.529+0800][0.001s][5235][debug][perf,datacreation]
Unified Logging 小結(jié)
輸出格式如下:
-Xlog:[selectors]:[output]:[decorators][:output-options]
-
selectors 是多個(gè) tag 和 level 的組合,起到了 what(過(guò)濾器)的作用,格式為
tag1[+tag2...][*][=level][,...]
- decorators 是日志相關(guān)的描述信息,也可以理解為上下文
- output 是輸出相關(guān)的選項(xiàng),一般我們會(huì)配置為輸出到文件,按文件大小切割
這里補(bǔ)充一個(gè)知識(shí)點(diǎn),就是默認(rèn)值:
- tag:all
- level:info
- output:stdout
- decorators: uptime, level, tags
GC 參數(shù)遷移
可以看到 GC 相關(guān)的參數(shù)都已經(jīng)收攏到 Xlog 下,以前的很多 Java8 下的參數(shù)已經(jīng)被移除或者標(biāo)記為過(guò)期。
比如 PrintGCDetails
已經(jīng)被 -Xlog:gc*
取代:
java-XX:+PrintGCDetails-version
[0.001s][warning][gc]-XX:+PrintGCDetailsisdeprecated.Willuse-Xlog:gc*instead.
常見(jiàn)的標(biāo)記為廢棄的參數(shù)還有 -XX:+PrintGC
和 -Xloggc:
,遷移前后的參數(shù)如下:
舊參數(shù) | 新參數(shù) |
---|---|
-XX:+PrintGCDetails | -Xlog:gc* |
-XX:+PrintGC | -Xlog:gc |
-Xloggc:
|
-Xlogfile= |
除此之外,大量的 GC 的參數(shù)被移除,比如常用的參數(shù) -XX:+PrintTenuringDistribution
,Java17 會(huì)拒絕啟動(dòng)
java-XX:+PrintTenuringDistribution-version
UnrecognizedVMoption'PrintTenuringDistribution'
Error:CouldnotcreatetheJavaVirtualMachine.
Error:Afatalexceptionhasoccurred.Programwillexit.
更詳細(xì)的移除的參數(shù)如下
CMSDumpAtPromotionFailure,
CMSPrintEdenSurvivorChunks,
GlLogLevel,
G1PrintHeapRegions,
G1PrintRegionLivenessInfo,
G1SummarizeConcMark,
G1SummarizeRSetStats,
G1TraceConcRefinement,
G1TraceEagerReclaimHumongousObjects,
G1TraceStringSymbolTableScrubbing,
GCLogFileSize,NumberofGCLogFiles,
PrintAdaptiveSizePolicy,
PrintclassHistogramAfterFullGC,
PrintClassHistogramBeforeFullGC,
PrintCMSInitiationStatistics
PrintCMSStatistics,
PrintFLSCensus,
PrintFLSStatistics,
PrintGCApplicationConcurrentTime
PrintGCApplicationStoppedTime,
PrintGCCause,
PrintGCDateStamps,
PrintGCID,
PrintGCTaskTimeStamps,
PrintGCTimeStamps,
PrintHeapAtGC,
PrintHeapAtGCExtended,
PrintJNIGCStalls,
PrintOldPLAB
PrintParallel0ldGCPhaseTimes,
PrintPLAB,
PrintPromotionFailure,
PrintReferenceGC,
PrintStringDeduplicationStatistics,
PrintTaskqueue,
PrintTenuringDistribution,
PrintTerminationStats,
PrintTLAB,
TraceDynamicGCThreads,
TraceMetadataHumongousAllocation,
UseGCLogFileRotation,
VerifySilently
這些移除的參數(shù)大部分都能在新的日志體系下找到對(duì)應(yīng)的參數(shù),比如 PrintHeapAtGC
這個(gè)參數(shù)可以用 -Xlog:gc+heap=debug
來(lái)替代
$java-Xlog:gc+heap=debug-cp.G1GCDemo01
[0.004s][debug][gc,heap]Minimumheap8388608Initialheap268435456Maximumheap
hello,g1gc!
[12.263s][debug][gc,heap]GC(0)HeapbeforeGCinvocations=0(full0):
[12.265s][debug][gc,heap]GC(0)garbage-firstheap
[12.265s][debug][gc,heap]GC(0)regionsize2048K,1young(2048K)
[12.265s][debug][gc,heap]GC(0)Metaspaceused3678K
[12.265s][debug][gc,heap]GC(0)classspaceused300K
[12.280s][debug][gc,heap]GC(0)Uncommittableregionsaftershrink:124
雖然理解起來(lái)不太直觀,不過(guò)要記住 -XX:+PrintGCApplicationStoppedTime
和 -XX+PrintGCApplicationConcurrentTime
這兩個(gè)參數(shù)一起被 -Xlog:safepoint
取代。
還有一個(gè)常見(jiàn)的參數(shù) -XX:+PrintAdaptiveSizePolicy
被 -Xlog:gc+ergo*=trace
取代,
[0.122s][debug][gc,ergo,refine]InitialRefinementZones:green:23,yellow:
69,red:115,minyellowsize:46
[0.142s][debug][gc,ergo,heap]Expandtheheap.requestedexpansionamount:268435456Bexpansionamount:268435456B
[2.475s][trace][gc,ergo,cset]GC(0)StartchoosingCSet.pendingcards:0predictedbasetime:10.00msremainingtime:
190.00mstargetpausetime:200.00ms
[2.476s][trace][gc,ergo,cset]GC(9)AddyoungregionstoCSet.eden:24regions,survivors:0regions,predictedyoung
regiontime:367.19ms,targetpausetime:200.00ms
[2.476s][debug][gc,ergo,cset]GC(0)FinishchoosingCSet.old:0regions,predictedoldregiontime:0.00ms,time
remaining:0.00
[2.826s][debug][gc,ergo]GC(0)RunningG1ClearCardTableTaskusing1workersfor1unitsofworkfor24regions.
[2.827s][debug][gc,ergo]GC(0)RunningG1FreeCollectionSetusing1workersforcollectionsetlength24
[2.828s][trace][gc,ergo,refine]GC(0)UpdatingRefinementZones:updaterstime:0.004ms,updatersbuffers:0,updaters
goaltime:19.999ms
[2.829s][debug][gc,ergo,refine]GC(0)UpdatedRefinementZones:green:23,yellow:69,red:115
[3.045s][trace][gc,ergo,set]GC(1)StartchoosingCSet.pendingcards:5898predictedbasetime:26.69msremaining
time:173.31mstargetpausetime:200.00ms
[3.045s][trace][gc,ergo,cset]GC(1)AddyoungregionstoSet.eden:9regions,survivors:3regions,predictedyoung
regiontime:457.38ms,targetpausetime:200.00ms
[3.045s][debug](gc,ergo,set]GC(1)FinishchoosingCSet.old:@regions,predictedoldregiontime:0.00ms,time
remaining:0.00
[3.090s][debug][gc,ergo
]GC(1)RunningG1ClearCardTableTaskusing1workersfor1unitsofworkfor12regions.
[3.091s][debug][gc,ergo
GC(1)RunningG1FreeCollectionSetusing1workersforcollectionsetlength12
[3.093s][trace][gc,ergo,refine]GC(1)UpdatingRefinementZones:updaterstime:2.510ms,updatersbuffers:25,updaters
goaltime:19.999ms
[3.093s][debug][gc,ergo,refine]GC(1)UpdatedRefinementZones:green:25,yellow:75,red:125
看一下這部分的源碼的變遷,就可以知道確實(shí)是如此了,在 Java8 中,PSYoungGen::resize_spaces
代碼如下:

在 Java17 中,這部分日志打印被 gc+ergo 的標(biāo)簽日志取代:

還有一個(gè)分代 GC 中非常有用的參數(shù) -XX:+PrintTenuringDistribution
,現(xiàn)在被 gc+age=trace
取代
完整的參數(shù)變遷對(duì)應(yīng)表如下:




舉例
-XX:+PrintGCDetails//gc*
-XX:+PrintGCApplicationStoppedTime//safepoint
-XX:+PrintGCApplicationConcurrentTime//safepoint
-XX:+PrintGCCause//默認(rèn)會(huì)輸出
-XX:+PrintGCID//默認(rèn)會(huì)輸出
-XX:+PrintTenuringDistribution//gc+age*=trace
-XX:+PrintGCDateStamps//:time,tags,level
-XX:+UseGCLogFileRotation//:filecount=5,filesize=10M
-XX:NumberOfGCLogFiles=5//:filecount=5,filesize=10M
-XX:GCLogFileSize=10M//:filecount=5,filesize=10M
-Xloggc:/var/log/`date+%FT%H-%M-%S`-gc.log//-Xlog::file=/var/log/%t-gc.log
變遷后:
-Xlog:
gc*,
safepoint,
gc+heap=debug,
gc+ergo*=trace,
gc+age*=trace,
:file=/var/log/%t-gc.log
:time,tags,level
:filecount=5,filesize=10M
推薦的配置
-Xlog:
//selections
codecache+sweep*=trace,
class+unload,//TraceClassUnloading
class+load,//TraceClassLoading
os+thread,
safepoint,//TraceSafepoint
gc*,//PrintGCDetails
gc+stringdedup=debug,//PrintStringDeduplicationStatistics
gc+ergo*=trace,
gc+age=trace,//PrintTenuringDistribution
gc+phases=trace,
gc+humongous=trace,
jit+compilation=debug
//output
:file=/path_to_logs/app.log
//decorators
:level,tags,time,uptime,pid
//output-options
:filesize=104857600,filecount=5
基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 實(shí)現(xiàn)的后臺(tái)管理系統(tǒng) + 用戶小程序,支持 RBAC 動(dòng)態(tài)權(quán)限、多租戶、數(shù)據(jù)權(quán)限、工作流、三方登錄、支付、短信、商城等功能
運(yùn)行相關(guān)
反射+私有 API 調(diào)用之傷
在 Java8 中,沒(méi)有人能阻止你訪問(wèn)特定的包,比如 sun.misc,對(duì)反射也沒(méi)有限制,只要 setAccessible(true) 就可以了。Java9 模塊化以后,一切都變了,只能通過(guò) --add-exports
和 --add-opens
來(lái)打破模塊封裝
-
--add-opens
導(dǎo)出特定的包 -
--add-opens
允許模塊中特定包的類路徑深度反射訪問(wèn)
比如:
--add-opensjava.base/java.lang=ALL-UNNAMED
--add-opensjava.base/java.io=ALL-UNNAMED
--add-opensjava.base/java.math=ALL-UNNAMED
--add-opensjava.base/java.net=ALL-UNNAMED
--add-opensjava.base/java.nio=ALL-UNNAMED
--add-opensjava.base/java.security=ALL-UNNAMED
--add-opensjava.base/java.text=ALL-UNNAMED
--add-opensjava.base/java.time=ALL-UNNAMED
--add-opensjava.base/java.util=ALL-UNNAMED
--add-opensjava.base/jdk.internal.access=ALL-UNNAMED
--add-opensjava.base/jdk.internal.misc=ALL-UNNAMED
關(guān)于 GC 算法的選擇
CMS 正式退出歷史舞臺(tái),G1 正式接棒,ZGC 蓄勢(shì)待發(fā)。在GC 算法的選擇上,目前來(lái)看 G1 還是最佳的選擇,ZGC 因?yàn)橛袃?nèi)存占用被 OS 標(biāo)記過(guò)高(三倍共享內(nèi)存)虛高的問(wèn)題,進(jìn)程可能被 OOM-killer 殺掉。
ZGC 三倍 RES 內(nèi)存
ZGC 底層用到了一個(gè)稱之為染色指針的技術(shù),使用三個(gè)視圖(Marked0、Marked1 和 Remapped)來(lái)映射到同一塊共享內(nèi)存區(qū)域,原理如下:
##include
##include
##include
##include
##include
##include
##include
intmain(){
//shm_open()函數(shù)用來(lái)打開(kāi)或者創(chuàng)建一個(gè)共享內(nèi)存區(qū),兩個(gè)進(jìn)程可以通過(guò)給shm_open()函數(shù)傳遞相同的名字以達(dá)到操作同一共享內(nèi)存的目的
intfd=::shm_open("/test",O_RDWR|O_CREAT|O_EXCL,0600);
if(fd0){
shm_unlink("/test");
perror("shmopenfailed");
return0;
}
size_tsize=1*1024*1024*1024;
//創(chuàng)建一個(gè)共享內(nèi)存后,默認(rèn)大小為0,所以需要設(shè)置共享內(nèi)存大小。ftruncate()函數(shù)可用來(lái)調(diào)整文件或者共享內(nèi)存的大小
::ftruncate(fd,size);
intprot=PROT_READ|PROT_WRITE;
//創(chuàng)建共享內(nèi)存后,需要將共享內(nèi)存映射到調(diào)用進(jìn)程的地址空間,可通過(guò)mmap()函數(shù)來(lái)完成
uint32_t*p1=(uint32_t*)(mmap(nullptr,size,prot,MAP_SHARED,fd,0));
uint32_t*p2=(uint32_t*)(mmap(nullptr,size,prot,MAP_SHARED,fd,0));
uint32_t*p3=(uint32_t*)(mmap(nullptr,size,prot,MAP_SHARED,fd,0));
::close(fd);
*p1=0xcafebabe;
::printf("Addressofaddr1:%p,valueis0x%x
",p1,*p1);
::printf("Addressofaddr2:%p,valueis0x%x
",p2,*p2);
::printf("Addressofaddr3:%p,valueis0x%x
",p3,*p3);
::getchar();
*p2=0xcafebaba;
::printf("Addressofaddr1:%p,valueis0x%x
",p1,*p1);
::printf("Addressofaddr2:%p,valueis0x%x
",p2,*p2);
::printf("Addressofaddr3:%p,valueis0x%x
",p3,*p3);
::getchar();
munmap(p1,size);
munmap(p2,size);
munmap(p3,size);
shm_unlink("/test");
std::cout<"hello"<std::endl;
}
你可以想象 p1、p2、p3 這三塊內(nèi)存區(qū)域就是 ZGC 中三種視圖。
但是在 linux 統(tǒng)計(jì)中,雖然是共享內(nèi)存,但是依然會(huì)統(tǒng)計(jì)三次,比如 RES。
同一個(gè)應(yīng)用,使用 G1 RES 顯示占用 2G,ZGC 則顯示占用 6G
java-XX:+AlwaysPreTouch-Xms2G-Xmx2G-XX:+UseZGCMyTest
java-XX:+AlwaysPreTouch-Xms2G-Xmx2G-XX:+UseG1GCMyTest

接下面我們討論的都是 G1 相關(guān)的。
G1 參數(shù)調(diào)整
不要配置新生代的大小
這個(gè)在《JVM G1 源碼分析和調(diào)優(yōu)》一書(shū)里有詳細(xì)的介紹,有兩個(gè)主要的原因:
- G1對(duì)內(nèi)存的管理是不連續(xù)的,重新分配一個(gè)分區(qū)代價(jià)很低
- G1 的需要根據(jù)目標(biāo)停頓時(shí)間動(dòng)態(tài)調(diào)整搜集的分區(qū)的個(gè)數(shù),如果不能調(diào)整新生代的大小,那么 G1 可能不能滿足停頓時(shí)間的要求
諸如 -Xmn, -XX:NewSize, -XX:MaxNewSize, -XX:SurvivorRatio
都不要在 G1 中出現(xiàn),只需要控制最大、最小堆和目標(biāo)暫停時(shí)間即可
調(diào)整 -XX:InitiatingHeapOccupancyPercent
到合適的值
IHOP 默認(rèn)值為 45,這個(gè)值是啟動(dòng)并發(fā)標(biāo)記的先決條件,只有當(dāng)老年代內(nèi)存??偪臻g的 45% 之后才會(huì)啟動(dòng)并發(fā)標(biāo)記任務(wù)。
增加這個(gè)值:導(dǎo)致并發(fā)標(biāo)記可能花費(fèi)更多的時(shí)間,同時(shí)導(dǎo)致 YGC 和 Mixed-GC 收集時(shí)的分區(qū)數(shù)變少,可以根據(jù)整體應(yīng)用占用的平均內(nèi)存來(lái)設(shè)置。
審核編輯 :李倩
-
JAVA
+關(guān)注
關(guān)注
20文章
2983瀏覽量
106524 -
編譯
+關(guān)注
關(guān)注
0文章
674瀏覽量
33614 -
遷移
+關(guān)注
關(guān)注
0文章
34瀏覽量
8023
原文標(biāo)題:從 Java 8 升級(jí)到 Java 17 全過(guò)程,賊特么坑!
文章出處:【微信號(hào):芋道源碼,微信公眾號(hào):芋道源碼】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
6.12.1升級(jí)到6.13老是閃退是什么原因?qū)е碌模?/a>
Java應(yīng)用OOM問(wèn)題的排查過(guò)程

Java 23功能介紹

Java集合API的改進(jìn)介紹

從ADS7813升級(jí)到ADS8513

java反編譯能拿到源碼嗎
將Non-OS SDK從1.3.0升級(jí)到1.4.0后,AT CWLAP命令將無(wú)法再找到我的AP,為什么?
華納云:java web和java有什么區(qū)別java web和java有什么區(qū)別

JDK8升級(jí)JDK11最全實(shí)踐干貨來(lái)了

JDK11升級(jí)JDK17最全實(shí)踐干貨來(lái)了

精準(zhǔn)到毫米:H9激光切管機(jī)鋁材切割與打孔全過(guò)程解析

評(píng)論