350: Dynamic CDS Archives
了解這個特性之前革砸,需要先了解一下跟它有很大關(guān)聯(lián)的特性JEP310:Application Class-Data Sharing,簡稱AppCDS。這個特性簡介就是為了改善JVM應(yīng)用的啟動速度和內(nèi)存占用,并且擴(kuò)展了CDS(Class-Data Sharing)特性從而允許應(yīng)用的類也可以被放置在共享的歸檔類(archived classes)文件中抄课。這個JEP310的主要目標(biāo)如下:
- 通過共享不同Java進(jìn)程之間通用的類元數(shù)據(jù)從而減少內(nèi)存占用磷账;
- 改進(jìn)啟動時間;
- 擴(kuò)展CDS從而允許歸檔類被加載到自定義類加載器中扫皱;
- 擴(kuò)展CDS允許歸檔類來自JDK運(yùn)行時鏡像文件($JAVA_HOME/lib/modules);
成功參考指標(biāo):
- 多JVM進(jìn)程能夠節(jié)省很大的內(nèi)存空間;
- 進(jìn)程的啟動時間提升明顯韩脑;
JEP350特性期望擴(kuò)展CDS氢妈,從而允許在Java應(yīng)用執(zhí)行后進(jìn)行動態(tài)類歸檔,歸檔的類將包括當(dāng)前默認(rèn)基礎(chǔ)CDS歸檔中不存在的應(yīng)用類和庫中的類扰才。這個特性的主要目標(biāo)有:
- 提高CDS的可用性允懂,消除了用戶使用時為每個應(yīng)用程序創(chuàng)建類列表(class list)的需要;
- 通過
-Xshare:dump
參數(shù)開啟靜態(tài)歸檔衩匣,包括內(nèi)建的類加載器和用戶自定義的類加載器蕾总。
在這之前,如果Java應(yīng)用要使用CDS的話琅捏,3個步驟是必須的:
- 執(zhí)行一次或者多次試運(yùn)行生百,從而創(chuàng)建一個class list;
- 通過使用創(chuàng)建的class list來dump一個歸檔(archive)柄延;
- 用這個歸檔來運(yùn)行蚀浆;
使用示例:
# JVM退出時動態(tài)創(chuàng)建共享歸檔文件
bin/java -XX:ArchiveClassesAtExit=hello.jsa -cp hello.jar Hello
# 用動態(tài)創(chuàng)建的共享歸檔文件運(yùn)行應(yīng)用
bin/java -XX:SharedArchiveFile=hello.jsa -cp hello.jar Hello
351: ZGC: Uncommit Unused Memory
增強(qiáng)ZGC特性,將沒有使用的堆內(nèi)存歸還給操作系統(tǒng)搜吧。ZGC當(dāng)前不能把內(nèi)存歸還給操作系統(tǒng)市俊,即使是那些很久都沒有使用的內(nèi)存,有點(diǎn)像貔貅一樣滤奈,只進(jìn)不出摆昧,哈哈。這種行為并不是對任何應(yīng)用和環(huán)境都是友好的蜒程,尤其是那些內(nèi)存占用敏感的服務(wù)绅你,例如:
- 按需付費(fèi)使用的容器環(huán)境;
- 應(yīng)用可能長時間閑置昭躺,并且和很多其他應(yīng)用共享和競爭資源的環(huán)境忌锯;
- 應(yīng)用在執(zhí)行期間有非常不同的堆空間需求,例如领炫,可能在啟動的時候比穩(wěn)定運(yùn)行的時候需要更多的內(nèi)存偶垮。
HotSpot的G1和Shenandoah這兩個GC已經(jīng)提供了這種能力,并且對某些用戶來說帝洪,非常有用似舵。因此,把這個特性引入ZGC會得到這些用戶的歡迎碟狞。
ZGC的堆又若干個Region組成,每個Region被稱之為ZPage婚陪。每個Zpage與數(shù)量可變的已提交內(nèi)存相關(guān)聯(lián)族沃。當(dāng)ZGC壓縮堆的時候,ZPage就會釋放,然后進(jìn)入page cache脆淹,即ZPageCache常空。這些在page cache中的ZPage集合就表示沒有使用部分的堆,這部分內(nèi)存應(yīng)該被歸還給操作系統(tǒng)盖溺±觳冢回收內(nèi)存可以簡單的通過從page cache中逐出若干個選好的ZPage來實(shí)現(xiàn),由于page cache是以LRU順序保存ZPage的烘嘱,并且按照尺寸(小昆禽,中,大)進(jìn)行隔離蝇庭,因此逐出ZPage機(jī)制和回收內(nèi)存相對簡單了很多醉鳖,主要挑戰(zhàn)是設(shè)計關(guān)于何時從page cache中逐出ZPage的策略。
一個簡單的策略就是設(shè)定一個超時或者延遲值哮内,表示ZPage被驅(qū)逐前盗棵,能在page cache中駐留多長時間。這個超時時間會有一個合理的默認(rèn)值北发,也可以通過JVM參數(shù)覆蓋它纹因。Shenandoah GC用了一個類型的策略,默認(rèn)超時時間是5分鐘琳拨,可以通過參數(shù)-XX:ShenandoahUncommitDelay = milliseconds覆蓋默認(rèn)值瞭恰。
像上面這樣的策略可能會運(yùn)作得相當(dāng)好。但是从绘,用戶還可以設(shè)想更復(fù)雜的策略:不需要添加任何新的命令行選項(xiàng)寄疏。 例如,基于GC頻率或某些其他數(shù)據(jù)找到合適超時值的啟發(fā)式算法僵井。JDK13將使用哪種具體策略目前尚未確定陕截。可能最初只提供一個簡單的超時策略批什,使用-XX:ZUncommitDelay = seconds選項(xiàng)农曲,以后的版本會添加更復(fù)雜、更智能的策略(如果可以的話)驻债。
uncommit能力默認(rèn)是開啟的乳规,但是無論指定何種策略,ZGC都不能把堆內(nèi)存降到低于Xms合呐。這就意味著暮的,如果Xmx和Xms相等的話,這個能力就失效了淌实,-XX:-ZUncommit這個參數(shù)也能讓這個內(nèi)存管理能力失效冻辩。
353: Reimplement the Legacy Socket API
用一個易于維護(hù)和Debug的猖腕,更簡單、更現(xiàn)代的實(shí)現(xiàn)來取代java.net.Socket和java.net.ServerSocket恨闪。Socket和ServerSocket可以追溯到JDK1.0倘感,它們的實(shí)現(xiàn)混合了Java和C代碼,維護(hù)和調(diào)試都非常痛苦咙咽。而且其實(shí)現(xiàn)用線程棧來進(jìn)行IO buffer老玛,導(dǎo)致某些場景需要調(diào)大Xss。
全新實(shí)現(xiàn)的NioSocketImpl钧敞,用來取代PlainSocketImpl蜡豹,它的優(yōu)點(diǎn)如下:
- 非常容易維護(hù)和Debug;
- 直接使用JDK的NIO實(shí)現(xiàn)犁享,不需要自己的本地代碼余素;
- 結(jié)合了buffer cache機(jī)制,所以不需要用線程棧來進(jìn)行IO操作炊昆;
- 用JUC的鎖取代synchronized修飾的方法桨吊;
354: Switch Expressions (Preview)
擴(kuò)展Switch表達(dá)式,既能用陳述的方式凤巨,也能用表達(dá)式的方式视乐。并且這兩種形式都可以用傳統(tǒng)方式(case ... : labels),或者新的方式(case ... -> labels)敢茁,并且還準(zhǔn)備引入表達(dá)式匹配(JEP305)佑淀,類似這種玩法:
if (obj instanceof String s && s.length() > 5) {
.. s.contains(..) ..
}
Switch表達(dá)式最初在JEP325中被提出,在JDK12中作為預(yù)覽特性彰檬,根據(jù)反饋伸刃,這次的JEP354相比JEP325有一些改變,新版Switch表達(dá)式用法參考如下:
switch (day) {
case MONDAY, FRIDAY, SUNDAY -> System.out.println(6);
case TUESDAY -> System.out.println(7);
case THURSDAY, SATURDAY -> System.out.println(8);
case WEDNESDAY -> System.out.println(9);
}
int numLetters = switch (day) {
case MONDAY, FRIDAY, SUNDAY -> 6;
case TUESDAY -> 7;
case THURSDAY, SATURDAY -> 8;
case WEDNESDAY -> 9;
};
355: Text Blocks (Preview)
即文本塊逢倍。文本塊就是指多行字符串捧颅,例如一段格式化后的xml、json等较雕。用戶不需要轉(zhuǎn)義碉哑,Java能自動搞定。這個需求是承接自JEP326亮蒋,JEP326已經(jīng)廢棄扣典。
JEP326使用`這個符號,例如:
String html = `<html>
<body>
<p>Hello World.</p>
</body>
</html>
`;
JEP355使用"""這個符號慎玖,例如:
String html = """
<html>
<body>
<p>Hello World.</p>
</body>
</html>
""";
JEP326廢除的原因:
JEP326時把注意力放在字符串的原始性上贮尖,但是現(xiàn)在意識到這種關(guān)注是錯誤的。因?yàn)樵创a中原始字符串跨多行是很常見的趁怔,但是在內(nèi)容中支付非轉(zhuǎn)義分隔符的代碼很大湿硝,這樣的話闰蛔,在用戶使用多行字符串的時候,效率就會受到影響图柏。原文如下:
because while raw string literals could easily span multiple lines of source code, the cost of supporting unescaped delimiters in their content was extreme. This limited the effectiveness of the feature in the multi-line use case
新版本文本塊特性的目標(biāo):
- 簡化表達(dá)多行字符串,不需要轉(zhuǎn)義任连;
- 增強(qiáng)可讀性蚤吹;
接下來展示幾種使用代碼塊特性前后的字符串申明方式。
- HTML示例
一維表達(dá)方式(舊):
String html = "<html>\n" +
" <body>\n" +
" <p>Hello, world</p>\n" +
" </body>\n" +
"</html>\n";
二維表達(dá)方式(新):
String html = """
<html>
<body>
<p>Hello, world</p>
</body>
</html>
""";
- SQL示例
一維表達(dá)方式(舊):
String query = "SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`\n" +
"WHERE `CITY` = 'INDIANAPOLIS'\n" +
"ORDER BY `EMP_ID`, `LAST_NAME`;\n";
二維表達(dá)方式(新):
String query = """
SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`
WHERE `CITY` = 'INDIANAPOLIS'
ORDER BY `EMP_ID`, `LAST_NAME`;
""";