求求你,不要更新了 | JDK 13:5 大新特性首發,等你來看
- 2019 年 10 月 4 日
- 筆記
做積極的人,而不是積極廢人!
源碼精品專欄
- 中文詳細注釋的開源項目
- RPC 框架 Dubbo 源碼解析
- 網絡應用框架 Netty 源碼解析
- 消息中間件 RocketMQ 源碼解析
- 數據庫中間件 Sharding-JDBC 和 MyCAT 源碼解析
- 作業調度中間件 Elastic-Job 源碼解析
- 分佈式事務中間件 TCC-Transaction 源碼解析
- Eureka 和 Hystrix 源碼解析
- Java 並發源碼
來源:阿飛的博客
- 350: Dynamic CDS Archives
- 351: ZGC: Uncommit Unused Memory
- 353: Reimplement the Legacy Socket API
- 354: Switch Expressions (Preview)
- 355: Text Blocks (Preview)
- 參考
350: Dynamic CDS Archives
了解這個特性之前,需要先了解一下跟它有很大關聯的特性JEP310:Application Class-Data Sharing,簡稱AppCDS。這個特性簡介就是為了改善JVM應用的啟動速度和內存佔用,並且擴展了CDS(Class-Data Sharing)特性從而允許應用的類也可以被放置在共享的歸檔類(archived classes)文件中。這個JEP310的主要目標如下:
- 通過共享不同Java進程之間通用的類元數據從而減少內存佔用;
- 改進啟動時間;
- 擴展CDS從而允許歸檔類被加載到自定義類加載器中;
- 擴展CDS允許歸檔類來自JDK運行時鏡像文件($JAVA_HOME/lib/modules);
成功參考指標:
- 多JVM進程能夠節省很大的內存空間;
- 進程的啟動時間提升明顯;
JEP350特性期望擴展CDS,從而允許在Java應用執行後進行動態類歸檔,歸檔的類將包括當前默認基礎CDS歸檔中不存在的應用類和庫中的類。這個特性的主要目標有:
- 提高CDS的可用性,消除了用戶使用時為每個應用程序創建類列表(class list)的需要;
- 通過
-Xshare:dump
參數開啟靜態歸檔,包括內建的類加載器和用戶自定義的類加載器。
在這之前,如果Java應用要使用CDS的話,3個步驟是必須的:
- 執行一次或者多次試運行,從而創建一個class list;
- 通過使用創建的class list來dump一個歸檔(archive);
- 用這個歸檔來運行;
使用示例:
# JVM退出時動態創建共享歸檔文件 bin/java -XX:ArchiveClassesAtExit=hello.jsa -cp hello.jar Hello # 用動態創建的共享歸檔文件運行應用 bin/java -XX:SharedArchiveFile=hello.jsa -cp hello.jar Hello
351: ZGC: Uncommit Unused Memory
增強ZGC特性,將沒有使用的堆內存歸還給操作系統。ZGC當前不能把內存歸還給操作系統,即使是那些很久都沒有使用的內存,有點像貔貅一樣,只進不出,哈哈。這種行為並不是對任何應用和環境都是友好的,尤其是那些內存佔用敏感的服務,例如:
- 按需付費使用的容器環境;
- 應用可能長時間閑置,並且和很多其他應用共享和競爭資源的環境;
- 應用在執行期間有非常不同的堆空間需求,例如,可能在啟動的時候比穩定運行的時候需要更多的內存。
HotSpot的G1和Shenandoah這兩個GC已經提供了這種能力,並且對某些用戶來說,非常有用。因此,把這個特性引入ZGC會得到這些用戶的歡迎。
ZGC的堆又若干個Region組成,每個Region被稱之為ZPage。每個Zpage與數量可變的已提交內存相關聯。當ZGC壓縮堆的時候,ZPage就會釋放,然後進入page cache,即ZPageCache。這些在page cache中的ZPage集合就表示沒有使用部分的堆,這部分內存應該被歸還給操作系統。回收內存可以簡單的通過從page cache中逐出若干個選好的ZPage來實現,由於page cache是以LRU順序保存ZPage的,並且按照尺寸(小,中,大)進行隔離,因此逐出ZPage機制和回收內存相對簡單了很多,主要挑戰是設計關於何時從page cache中逐出ZPage的策略。
一個簡單的策略就是設定一個超時或者延遲值,表示ZPage被驅逐前,能在page cache中駐留多長時間。這個超時時間會有一個合理的默認值,也可以通過JVM參數覆蓋它。Shenandoah GC用了一個類型的策略,默認超時時間是5分鐘,可以通過參數-XX:ShenandoahUncommitDelay = milliseconds覆蓋默認值。
像上面這樣的策略可能會運作得相當好。但是,用戶還可以設想更複雜的策略:不需要添加任何新的命令行選項。例如,基於GC頻率或某些其他數據找到合適超時值的啟發式算法。JDK13將使用哪種具體策略目前尚未確定。可能最初只提供一個簡單的超時策略,使用**-XX:ZUncommitDelay = seconds**選項,以後的版本會添加更複雜、更智能的策略(如果可以的話)。
uncommit能力默認是開啟的,但是無論指定何種策略,ZGC都不能把堆內存降到低於Xms。這就意味着,如果Xmx和Xms相等的話,這個能力就失效了,-XX:-ZUncommit這個參數也能讓這個內存管理能力失效。
353: Reimplement the Legacy Socket API
用一個易於維護和Debug的,更簡單、更現代的實現來取代java.net.Socket和java.net.ServerSocket。Socket和ServerSocket可以追溯到JDK1.0,它們的實現混合了Java和C代碼,維護和調試都非常痛苦。而且其實現用線程棧來進行IO buffer,導致某些場景需要調大Xss。
全新實現的NioSocketImpl,用來取代PlainSocketImpl,它的優點如下:
- 非常容易維護和Debug;
- 直接使用JDK的NIO實現,不需要自己的本地代碼;
- 結合了buffer cache機制,所以不需要用線程棧來進行IO操作;
- 用JUC的鎖取代synchronized修飾的方法;
354: Switch Expressions (Preview)
擴展Switch表達式,既能用陳述的方式,也能用表達式的方式。並且這兩種形式都可以用傳統方式(case … : labels),或者新的方式(case … -> labels),並且還準備引入表達式匹配(JEP305),類似這種玩法:
if (obj instanceof String s && s.length() > 5) { .. s.contains(..) .. }
Switch表達式最初在JEP325中被提出,在JDK12中作為預覽特性,根據反饋,這次的JEP354相比JEP325有一些改變,新版Switch表達式用法參考如下:
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等。用戶不需要轉義,Java能自動搞定。這個需求是承接自JEP326,JEP326已經廢棄。
JEP326使用**`**這個符號,例如:
String html = `<html> <body> <p>Hello World.</p> </body> </html> `;
JEP355使用**"""**這個符號,例如:
String html = """ <html> <body> <p>Hello World.</p> </body> </html> """;
JEP326廢除的原因:JEP326時把注意力放在字符串的原始性上,但是現在意識到這種關注是錯誤的。因為源碼中原始字符串跨多行是很常見的,但是在內容中支付非轉義分隔符的代碼很大,這樣的話,在用戶使用多行字符串的時候,效率就會受到影響。原文如下:
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
新版本文本塊特性的目標:
- 簡化表達多行字符串,不需要轉義;
- 增強可讀性;
接下來展示幾種使用代碼塊特性前後的字符串申明方式。
- HTML示例
一維表達方式(舊):
String html = "<html>n" + " <body>n" + " <p>Hello, world</p>n" + " </body>n" + "</html>n";
二維表達方式(新):
String html = """ <html> <body> <p>Hello, world</p> </body> </html> """;
- SQL示例
一維表達方式(舊):
String query = "SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`n" + "WHERE `CITY` = 'INDIANAPOLIS'n" + "ORDER BY `EMP_ID`, `LAST_NAME`;n";
二維表達方式(新):
String query = """ SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB` WHERE `CITY` = 'INDIANAPOLIS' ORDER BY `EMP_ID`, `LAST_NAME`; """;
參考
參考地址:https://openjdk.java.net/projects/jdk/13/
如果你喜歡這篇文章,喜歡,轉發。
生活很美好,明天見(。・ω・。)ノ♡