0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

從Java 8升級(jí)到Java 17全過程

jf_ro2CN3Fa ? 來源:芋道源碼 ? 作者:芋道源碼 ? 2022-11-03 14:13 ? 次閱讀


最近在做 Java8 到 Java17 的遷移工作,前期做了一些準(zhǔn)備,但是在升級(jí)過程還是有些問題,太emo了,一些信息記錄如下,分為幾個(gè)部分:

  • 編譯相關(guān)
  • 參數(shù)遷移相關(guān)
  • 運(yùn)行相關(guān)

前人栽樹后人乘涼,有需要升級(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è)簡單,替換一下工具類即可。

[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 版本開始支持 Java17 的字節(jié)碼,低于 1.6.0 的編譯會(huì)直接報(bào)錯(cuò)

廢棄依賴分析

可以用 jdeps --jdk-internals --multi-release 17 --class-path . encloud-api.jar 來做項(xiàng)目的依賴分析

1743ec08-5b3e-11ed-a3b6-dac502259ad0.jpg

這樣你就可以知道哪些庫需要做升級(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)一的編程接口,讓用戶可以通過簡單的配置實(shí)現(xiàn)日志輸出的個(gè)性化配置,比如日志 tag、級(jí)別(info、debug 等)、上下文(線程 id、行號(hào)、時(shí)間等),在 JVM 內(nèi)部之前一直缺乏這樣的規(guī)范,于是出來了 Unified Logging,實(shí)現(xiàn)了日志格式的大一統(tǒng),這就是我們接下來要介紹的重點(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é)果如下:

174f20b4-5b3e-11ed-a3b6-dac502259ad0.jpg

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

17663646-5b3e-11ed-a3b6-dac502259ad0.jpg

歸根到底,日志打印,需要回答清楚三個(gè)問題:

  • what:要輸出什么信息(tag),以什么日志級(jí)別輸出(level)
  • where:輸出到哪里(console 還是 file)
  • decorators:日志如何

輸出什么信息(selectors)

首先來看 what 的部分,如何指定要輸出哪些信息,這個(gè)在 JVM 內(nèi)部被稱之為 selectors。

JVM 采用的是 =的形式來表示 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 的日志信息。

不過這里有一個(gè)比較坑的點(diǎn)是,這里的 tag 匹配規(guī)則是精確匹配,如果某條日志的 tag 是 gc,metaspace,通過上面的規(guī)則是匹配不到的,我們可以手動(dòng)指定的方式來輸出。

$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í)輸出 gcgc+metaspace 這兩類 tag 的日志,就可以這么寫:

$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 提供了通配符 * 來解決精確匹配的問題,比如我們想要所有 tag 為 gc 的日志,可以這么寫:

$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 來找到所有可用的 tag。

階段性小結(jié)

17736456-5b3e-11ed-a3b6-dac502259ad0.jpg

第二部分:輸出到哪里(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)。

178ecf0c-5b3e-11ed-a3b6-dac502259ad0.png

比如可以用 java -Xlog:all=debuglevel,tags,time,uptime,pid -version 選項(xiàng)來打印日志。

[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(過濾器)的作用,格式為 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)記為過期。

比如 PrintGCDetails 已經(jīng)被 -Xlog:gc* 取代:

java-XX:+PrintGCDetails-version

[0.001s][warning][gc]-XX:+PrintGCDetailsisdeprecated.Willuse-Xlog:gc*instead.

常見的標(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 來替代

$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

雖然理解起來不太直觀,不過要記住 -XX:+PrintGCApplicationStoppedTime-XX+PrintGCApplicationConcurrentTime 這兩個(gè)參數(shù)一起被 -Xlog:safepoint 取代。

還有一個(gè)常見的參數(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代碼如下:

179dedd4-5b3e-11ed-a3b6-dac502259ad0.jpg

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

17aae3b8-5b3e-11ed-a3b6-dac502259ad0.jpg

還有一個(gè)分代 GC 中非常有用的參數(shù) -XX:+PrintTenuringDistribution,現(xiàn)在被 gc+age=trace 取代

完整的參數(shù)變遷對(duì)應(yīng)表如下:

17c35902-5b3e-11ed-a3b6-dac502259ad0.png17dd64dc-5b3e-11ed-a3b6-dac502259ad0.png18028df2-5b3e-11ed-a3b6-dac502259ad0.png18105270-5b3e-11ed-a3b6-dac502259ad0.png
舉例
-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)限、工作流、三方登錄、支付、短信、商城等功能

  • 項(xiàng)目地址:https://gitee.com/zhijiantianya/yudao-cloud
  • 視頻教程:https://doc.iocoder.cn/video/

運(yùn)行相關(guān)

反射+私有 API 調(diào)用之傷

在 Java8 中,沒有人能阻止你訪問特定的包,比如 sun.misc,對(duì)反射也沒有限制,只要 setAccessible(true) 就可以了。Java9 模塊化以后,一切都變了,只能通過 --add-exports--add-opens 來打破模塊封裝

  • --add-opens 導(dǎo)出特定的包
  • --add-opens 允許模塊中特定包的類路徑深度反射訪問

比如:

--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 蓄勢待發(fā)。在GC 算法的選擇上,目前來看 G1 還是最佳的選擇,ZGC 因?yàn)橛袃?nèi)存占用被 OS 標(biāo)記過高(三倍共享內(nèi)存)虛高的問題,進(jìn)程可能被 OOM-killer 殺掉。

ZGC 三倍 RES 內(nèi)存

ZGC 底層用到了一個(gè)稱之為染色指針的技術(shù),使用三個(gè)視圖(Marked0、Marked1 和 Remapped)來映射到同一塊共享內(nèi)存區(qū)域,原理如下:

##include
##include
##include
##include
##include
##include
##include

intmain(){
//shm_open()函數(shù)用來打開或者創(chuàng)建一個(gè)共享內(nèi)存區(qū),兩個(gè)進(jìn)程可以通過給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ù)可用來調(diào)整文件或者共享內(nèi)存的大小
::ftruncate(fd,size);
intprot=PROT_READ|PROT_WRITE;
//創(chuàng)建共享內(nèi)存后,需要將共享內(nèi)存映射到調(diào)用進(jìn)程的地址空間,可通過mmap()函數(shù)來完成
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
181e2738-5b3e-11ed-a3b6-dac502259ad0.jpg

接下面我們討論的都是 G1 相關(guān)的。

G1 參數(shù)調(diào)整

不要配置新生代的大小

這個(gè)在《JVM G1 源碼分析和調(diào)優(yōu)》一書里有詳細(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)存來設(shè)置。



審核編輯 :李倩


聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • JAVA
    +關(guān)注

    關(guān)注

    19

    文章

    2943

    瀏覽量

    104100
  • 編譯
    +關(guān)注

    關(guān)注

    0

    文章

    646

    瀏覽量

    32670
  • 遷移
    +關(guān)注

    關(guān)注

    0

    文章

    33

    瀏覽量

    7905

原文標(biāo)題:從 Java 8 升級(jí)到 Java 17 全過程,賊特么坑!

文章出處:【微信號(hào):芋道源碼,微信公眾號(hào):芋道源碼】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    將Non-OS SDK1.3.0升級(jí)到1.4.0后,AT CWLAP命令將無法再找到我的AP,為什么?

    將Non-OS SDK1.3.0升級(jí)到1.4.0(AT版本0.40升級(jí)到0.50)后,AT CWLAP命令將無法再找到我的AP。它仍然會(huì)找到一些 AP,但不是我想使用的 AP,它在物理上最接近
    發(fā)表于 07-17 06:00

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

    應(yīng)用程序的運(yùn)行速度。綜合評(píng)估,Java 8 升級(jí)到 Java 11,G1GC平均速度提升16.1%,ParallelGC為4.5%(基于O
    的頭像 發(fā)表于 06-25 14:51 ?274次閱讀
    JDK<b class='flag-5'>8</b><b class='flag-5'>升級(jí)</b>JDK11最全實(shí)踐干貨來了

    如何將stm32f207的以太網(wǎng)庫中l(wèi)wip1.3.2升級(jí)到1.4.1?

    如何將stm32f207的以太網(wǎng)庫中l(wèi)wip1.3.2升級(jí)到1.4.1
    發(fā)表于 05-17 08:04

    STM32CubeMX版本升級(jí)由6.2.1升級(jí)到6.3.0后原工程重新編譯code文件變大什么原因?

    STM32CubeMX版本升級(jí)由6.2.1升級(jí)到6.3.0后原工程重新編譯code文件變大什么原因
    發(fā)表于 04-02 07:31

    關(guān)于2023年Java趨勢的內(nèi)容

    Java 17+ 被重新歸類為 Java 17,仍處于 早期采用者 階段,因?yàn)橛懈嗟目蚣軐?Java
    的頭像 發(fā)表于 12-13 11:17 ?379次閱讀
    關(guān)于2023年<b class='flag-5'>Java</b>趨勢的內(nèi)容

    idea怎么創(chuàng)建Java項(xiàng)目

    創(chuàng)建Java項(xiàng)目是一個(gè)相對(duì)較為復(fù)雜的過程,需要考慮各種細(xì)節(jié)和步驟。本文將詳細(xì)介紹如何創(chuàng)建一個(gè)Java項(xiàng)目。 一、準(zhǔn)備工作 在創(chuàng)建Java項(xiàng)
    的頭像 發(fā)表于 12-06 14:09 ?745次閱讀

    簡單了解Java的新特性

    Java 8 Java 20,Java 已經(jīng)走過了漫長的道路,自
    的頭像 發(fā)表于 11-23 16:38 ?867次閱讀
    簡單了解<b class='flag-5'>Java</b>的新特性

    java內(nèi)存溢出排查方法

    Java內(nèi)存溢出(Memory overflow)是指Java虛擬機(jī)(JVM)中的堆內(nèi)存無法滿足對(duì)象分配的需求,導(dǎo)致程序拋出OutOfMemoryError異常。內(nèi)存溢出是Java開發(fā)過程
    的頭像 發(fā)表于 11-23 14:46 ?2387次閱讀

    用C語言開發(fā)DSP系統(tǒng)全過程

    電子發(fā)燒友網(wǎng)站提供《用C語言開發(fā)DSP系統(tǒng)全過程.pdf》資料免費(fèi)下載
    發(fā)表于 11-18 10:57 ?0次下載
    用C語言開發(fā)DSP系統(tǒng)<b class='flag-5'>全過程</b>

    用C語言開發(fā)DSP系統(tǒng)的全過程講解

    電子發(fā)燒友網(wǎng)站提供《用C語言開發(fā)DSP系統(tǒng)的全過程講解.pdf》資料免費(fèi)下載
    發(fā)表于 11-18 10:53 ?0次下載
    用C語言開發(fā)DSP系統(tǒng)的<b class='flag-5'>全過程</b>講解

    JDK11升級(jí)JDK17最全實(shí)踐

    2021年9月14日,Oracle發(fā)布了可以長期支持的JDK17版本,那么JDK11JDK17,到底帶來了哪些特性呢?亞毫秒級(jí)的ZGC效
    的頭像 發(fā)表于 11-17 10:36 ?1309次閱讀
    JDK11<b class='flag-5'>升級(jí)</b>JDK<b class='flag-5'>17</b>最全實(shí)踐

    RT-Thread啟動(dòng)進(jìn)入就緒態(tài)最高優(yōu)先級(jí)線程的全過程與棧幀分析(上)

    本文簡單討論RT-Thread在啟動(dòng)后,逐步進(jìn)入到處于就緒態(tài)最高優(yōu)先級(jí)main線程的全過程。部分內(nèi)容涉及匯編指令,但通俗易懂。
    的頭像 發(fā)表于 11-08 12:47 ?1050次閱讀
    RT-Thread啟動(dòng)進(jìn)入就緒態(tài)最高優(yōu)先<b class='flag-5'>級(jí)</b>線程的<b class='flag-5'>全過程</b>與棧幀分析(上)

    Java11和Java17使用率達(dá)48%和45%

    2018 年 9 月發(fā)布的 Java 11 和 2020 年 9 月發(fā)布的 Java 17 是使用最廣泛的 Java 版本,使用率分別為 48% 和 45%。其次是 2014 年 3
    的頭像 發(fā)表于 11-01 12:30 ?486次閱讀

    java 8的日期用法

    java 已經(jīng)出到 17 了,而小編還在用 8 的版本,在 8 中已經(jīng)推出了新的日期 API,不在使用 。java.time 包下提供了用于
    的頭像 發(fā)表于 10-09 15:50 ?349次閱讀

    Java時(shí)間類轉(zhuǎn)換方案

    眾所周知,Java 8 之前的 Date 相關(guān)的時(shí)間類非常的不好用。 Java 8 之后開始加入了 LocalDate 等一系列更加現(xiàn)代化
    的頭像 發(fā)表于 10-09 15:48 ?402次閱讀