JDK 24 的首項公開功能 JEP 472 為限制使用 JNI 做準備

JDK 24 with JEP 472 page

JDK 24 現況

JDK 23站內介紹)即將於今年 9 月份發布,緊接著後續的 JDK 24 開發工作也已如火如荼地展開,並預計於 2025 年 3 月發布。JDK 24 屬於非長期支援(LTS)的版本之一,這意味著它與 JDK 23 一樣,將只會獲得 Oracle 六個月的 Premier 支援。

可以預期的是,許多已包含在 JDK 23 中的預覽功能,都可望被納入 JDK 24 之中,例如像是:

除了上述所列的預覽功能之外,JDK 24 第一個出爐的新功能是 JEP 472 Prepare to Restrict the Use of JNI(限制 JNI 使用的準備)

JEP 472 簡介

JEP 472 的任務是「限制 Java Native Interface 使用」的準備工作。當我們使用 JNI 時,JVM 就會發出警告。JDK 22 中引入的外部函式和記憶體 API(JEP 454 Foreign Function & Memory API,作為 JNI 替代方案)也同樣包含在內,因此使用 FFM API 時也會發出警告。其目的是幫助我們為未來的 Java 版本做好準備,並透過統一限制 JNI 和 FFM API 的使用來確保預設情況下的完整性。我們在必要時可以透過選擇性地指定選項來避免產生警告(現在階段)和禁止執行的限制(未來階段)。

該功能的目標有:

  • 保留 JNI 作為與原生程式碼相互操作的標準方式
  • 預設不允許與原生程式碼互動,無論是使用 JNI 或 FFM API,除非我們在程式啟動時明確指定啟用 JNI 或 FFM API
  • 調整 JNI 和 FFM API 的使用,讓函式庫的維護人員能順利轉移而無需開發人員變更命令列選項
  • 它並非要棄用 JNI,也並非要從 Java 平台中移除 JNI,同時也沒有要限制 JNI 呼叫原生程式碼

JNI 的問題

JNI 是在 JDK 1.1 時引入的,目的是做為 Java 程式碼與原生程式碼之間互相操作的主要方式。它允許 Java 程式碼呼叫原生程式碼(下行呼叫、downcall),以及原生程式碼呼叫 Java 程式碼(上行呼叫、upcall)。不幸的是,它們之間的任何交互操作都是有風險的,很可能會損害應用程式和 Java 平台本身的完整性。根據「預設情況下的完整性」政策,所有能夠破壞完整性的 JDK 功能都必須獲得開發人員的允許。下面列出了四種交互操作的風險:

  1. 下行呼叫可能導致任意的未定義行為,包括 JVM 當機。這些問題無法在 Java 執行時期預防,也無法拋出異常讓 Java 程式碼有機會去捕獲並處理
  2. 原生程式碼和 Java 程式碼之間經常利用直接位元組緩衝區交換資料,而這些緩衝區是垃圾收集器無法觸及的記憶體區域,最終變成了未受控管的灰色地帶。原生程式碼可能會產生一個無效記憶體區域的位元組緩衝區,如果在 Java 程式碼中使用它的話會導致未定義的行為
  3. 原生程式碼可以用 JNI 繞過 JVM 的存取檢查,像是直接存取欄位與呼叫方法。另外,原生程式碼甚至可以利用 JNI 在 final 欄位初始化很久之後去更改它們的值。因此,呼叫原生程式碼具有破壞 Java 程式碼完整性的風險存在
  4. 原生程式碼如果不正確使用某些 JNI 函數,可能導致垃圾收集器出現不良行為,而這種行為可能在程式的任何生命週期階段中發生。例如,存取臨界區域(critical region)但卻未釋放它,導致垃圾收集區無法回收物件

在 JDK 22 引入的 FFM API 一樣具有上述前二項的風險。採取的應對策略是將可能破壞完整性和不會破壞完整性的操作分開,因此 FFM API 之中有部分被歸類為受到限制的方法。這代表在程式執行時,我們必須使用 java 命令列選項去解開它們的封印。JNI 也應該要效仿 FFM API,以實現預設情況下的完整性。

後續版本

下一個 LTS 版本 JDK 25 預計將於 2025 年 9 月發布。以目前的使用現況來看,LTS 版本在 Java 社群中的使用比例佔據了極高的主導地位。以 New Relic 在今年 4 月的報告(來源)來看,至少有 98% 以上的用戶採用 Java LTS 版本,包括 8、11、17 和 21。這意味著 JDK 23 和 JDK 24 的採用率應該會非常低,因為大部分的用戶會期望使用 LTS,也就是接下來的 JDK 25。

本篇文章的內容為老喬原創、二創或翻譯而來。雖已善盡校對、順稿與查核義務,但人非聖賢,多少仍會有疏漏之處難以避免。如果大家有任何問題、建議或指教,都歡迎在底下留言與老喬討論!

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

seven − 6 =

返回頂端