畢昇 JDK:爲啥是ARM 上超好用的 JDK

摘要:畢昇 JDK 是華爲基於 OpenJDK 定製的開源版本,是一款高性能、可用於生產環境的 OpenJDK 發行版。java

本文分享自華爲雲社區《【雲駐共創】畢昇 JDK:「傳奇再現」華爲如何打造 ARM 上最好用的 JDK》,原文做者:白鹿第一帥。git

前言

不知道你們是否據說過亦或是使用過畢昇 JDK,是否從事 Java 工做?是否從事 JVM 底層開發?絕大多數 Java 開發者使用的都是 Oracle 的 JDK 或者是 OpenJDK,本文咱們將介紹華爲的畢昇 JDK 以及咱們所作的相關技術優化,但願能在除上述二者以外提供給你們新的選擇。程序員

1、什麼是畢昇 JDK

 

1.1、畢昇 JDK 發展歷程

畢昇 JDK 是華爲基於 OpenJDK 定製的開源版本,是一款高性能、可用於生產環境的 OpenJDK 發行版。穩定運行在華爲內部 500 多個產品上,在華爲內部普遍使用畢昇 JDK,團隊積累了豐富的開發經驗,解決了實際業務運行中遇到的多個疑難問題。如 crash 等相關問題,咱們已經在內部解決。算法

1.2、畢昇 JDK 的支持架構

  • 目前僅支持 Linux/AArch64 架構。歡迎廣大開發者小夥伴們下載使用。
  • 目前畢昇 JDK 支持 8 11 兩個 LTS 版本,而且已經所有開源。

1.3、畢昇 JDKOpenJDK Oracle JDK 區別

咱們經過對比和分析畢昇 JDKOpenJDK Oracle JDK,來幫助你們在挑選 JDK 時有更好的選擇。數組

以下圖所示,咱們用藍色的區域表明 OpenJDK,淺黃色和紅色分別表明 Oracle JDK 和畢昇 JDK安全

以上圖爲參考,咱們能夠發現:服務器

  • 畢昇 JDK Oracle JDK 同樣,都是基於 OpenJDK 定製獲得,可是又同時賦予了各自不一樣的商業特性。好比,咱們都知道 OpenJDK 12 添加了一個的新垃圾收集(GC)算法——Shenandoah,可是在 Oracle JDK 的發行中是沒有附帶的。
  • 畢昇 JDK 在基於 OpenJDK 定製的基礎上,存在的些許區別,主要來源於對產品功能的一些加強、問題的修復以及和上游特性的合入。

2、爲何要作畢昇 JDK

2.1Oracle JDK 受權方式發生變化

  • 除去你們衆所周知的緣由以外,不知道你們是否知道,Oracle JDK 8u212 版本以後是收費的。於公司而言,結合 JDK 自身存在的安全漏洞問題,綜合商業因素考慮的結果就是研發符合自身發展的 JDK

注:以上數據來自 Oracle 官網。多線程

2.2、高版本 JDK 有價值特性的渴望

JDK 每六個月發行一次新版本,JDK 版本衆多,不一樣功能/特性在不一樣 JDK 版本。程序員指望在最熟悉的 JDK 上儘量多的使用高版本中有價值的特性。例如 G1 GC JDK12 中引入了一個特性,把不使用的內存歸還給操做系統,該特性在雲場景中很是有價值,目前主流使用的仍是 JDK8,自研 JDK Blckport 特性能快速知足需求。架構

2.3、應用的定製化優化訴求

應用在運行的硬件、場景有特殊的訴求,但這些訴求短時間難以進入到社區。例如大數據應用在數學方面有較高訴請求,在自研 JDK 中能夠針對數學計算作循環開展、指令優化等編譯優化技術,加速計算。併發

3、畢昇 JDK 現狀

3.1、畢昇 JDK 研發現狀

  • 畢昇 JDK Oracle JDK 同樣,都是基於開源 OpenJDK 定製獲得。同時團隊爲上游社區貢獻了很多有價值的
    Patch,涉及到:垃圾回收、JIT、運行時內容等。
  • 畢昇 JDK 遵循 GPLv2 版權進行開源,而且能夠從官方免費下載二進制。
  • 畢昇 JDK採用社區化開發和運營,雙週會議,目前有 ARM、寶蘭德、麒麟等小夥伴一塊兒參與。畢昇 JDK 社區不只僅支持 ARM 平臺,任何關於 JDK 的問題均可以在畢昇 JDK 社區討論,都會在第一時間獲得回覆。
  • 在上游社區中,團隊目前有 Reviewer 1 名,Committer 1名,Author 8 名共 10 餘名同事往社區提交代碼。
  • 畢昇 JDK ARM 上性能、穩定性表現優異。

3.2、畢昇 JDK 性能提高實例

咱們經過在測試環境下運行畢昇 JDK 來分析其優點何在,測試環境以下:

  • ModelTaishan 2280V2
  • OSopenEuler20.09
  • HWkenpeng 920-6426 2600MHz128 cores
  • JDKJDK8U262

咱們經過比較在 SPECjbb 上的數據能夠發現畢昇 JDK critical max 上均有較大的提高:critical 提高 55%max 提高 16%

另外一方面,在 SPECjvm 上的數據雖說與上面相比並非特別明顯,可是仍平均提高 4.6%

4、畢昇 JDK GC 算法優化

4.1、並行複製算法的概念

咱們都知道複製是 GC 算法裏面很重要的一部分,特別是對於新生代的複製:將 from 區中的活躍對象複製到 to 區中,串行復制算法是僅有一個線程負責這個事情,而這沒法知足咱們的須要。因此咱們用到了並行複製算法,那麼什麼是並行複製算法呢?

  • 對象 A B 在並行複製算法中被不一樣的線程複製,可能因爲:對象 A B 有不一樣到達路徑,不一樣的線程複製。由於任務均衡的問題,線程能夠竊取其餘線程的複製任務。
  • 例若有兩個線程 T1 T2 分別複製對象 A BT1A→A´T2B→B´
  • 在複製時除了複製對象的內容外,還須要使用一個指針(Forwarding Pointer)記錄對象轉移後地址,防止對象被重複複製。

4.2、架構對並行複製算法的影響

  • 多線程的並行工做須要考慮不一樣架構的內存模型。X86 是一種強內存序架構,ARM 則是一種弱內存序,它們的內存序以下表所示:

  • 對於並行複製算法來講,在弱內存序架構下,因爲內存序的設計,其餘線程可能先觀測到轉移指針已經更新,可是對象還沒有複製。爲保證一致性,須要在複製和更新對象頭之間插入 membar,在 JVM 關於對象頭更新統一抽象爲 CAS 函數。
  • CAS 在不一樣的體系結構實現不一樣,X86 中採用 cmpxchgl 指令;ARM 中採用 Ldaxr/Stlxr 指令。

4.3、並行複製算法的流程

並行複製算法的流程圖以下圖所示:

  • 拷貝對象 obj 到新的對象位置 new_obj
  • 插入 Memory Barrier,對象 obj 經過 CAS 設置轉移指針,若成功則執行(3),失敗執行(4);
  • new_obj 的引用壓入棧中,返回 new_obj
  • 撤銷以前分配的對象,將 cas 成功線程的 new_obj 返回。

在熱點分析中,咱們發現複製操做的 60% CPU 消耗在插入 Memory Barrier 上。

4.4、算法優化減小 membar Q&A

Q:若是不插入 Memory barrier,多個線程觀察到內存不一致的狀況,在什麼狀況下會引入問題?
A

  • T1:還沒有完成對象複製,可是已經將對象入棧。
  • T2:從 T1 的線程棧竊取待複製的對象,並對還沒有完成複製的對象進行成員變量的複製更新,致使數據不一致。

Q:對於不須要複製成員變量的對象(例如:對象的成員變量所有是非引用類型;對象的成員變量其引用類型所有爲NULL,對象自己是原始類型的數組),還有必要使用 Memory Barrier?
A NO

Q 如何識別這些對象?
A

  • 靜態分析對象:能夠發現對象的成員變量所有是非引用類型、原始類型的數組。已經開源。
  • 動態分析對象:經過屏障技術識別。

經過對於並行複製算法的優化,咱們分別在 SPECjbb SPECjvm 達到了較好的預期成果,以下圖所示:

4.5G1GC 的優化

針對 G1 Full GC 優化,Full GC 分爲 4 個階段,分別是:

  • Mark:標記整個堆空間的活躍對象,並記錄活躍對象。
  • Prepare:計算每一個活躍對象在就地壓縮後的位置。
  • Adjust:根據對象新的地址,調整對象成員變量的引用位置。
  • Compact:複製對象的內存數據。

Compact 階段通常是最爲耗時的,涉及到內存數據的移動。那麼 可否在容許必定浪費空間的前提下,對於活躍對象多的部分分區不移動或者少移動,從而提升算法效率? 咱們對活躍對象做下圖:


咱們能夠發現:

  • 分區活躍對象佔比符合 U 型分佈。
  • Benchmark 進行研究,有 41.27% 分區活躍對象佔比在 98%
  • 減小對象的移動在必定程度上也符合強分代理論的假設。
  • 測試發現,對於相似的應用性能有 3~5% 的提升。

咱們已經將相關代碼貢獻到社區,歡迎你們前往查看。

4.6ZGC 的優化

  • 畢昇 JDK 11 是第一個在 ARM 架構中支持 ZGC JDK
  • ZGC 的目標是管理 TB 級內存,且垃圾回收的停頓時間控制在 10 毫秒。ZGC 的回收過程包括 3 步,分別是:併發標記(Mark)、併發轉移(Relocate)和併發重定位(Remap)。在轉移的過程,爲了提升轉移的效率,只有當頁面的垃圾回收空間達到必定比例纔會參與轉移。目前的實現中比例經過參數 ZFragmentLimit 控制,該參數的默認值爲 25
  • 如何設置 ZFragmentLimit?過大,內存浪費;太小,回收效率低下。
  • GC 執行的過程當中收集轉移的信息(內存轉移的速率、轉移耗時),並預測下一次 GC 能夠轉移的內存,使用預測值來控制哪些頁面能夠參與轉移。以下圖所示:

  • 計算內存的轉移速率:

  • 預測本次 GC 的轉移速率:

  • 使用正態分佈,並輔以 99% 的置信度。
  • 預測本次 GC 的轉移耗時:

  • 預測本次 GC 的轉移字節:

  • 對於 Benchmark 的測試代表,效果 3~5% 的提高,代碼已經開源,正在往社區同步。

5、JIT 優化——SVE 算法優化

5.1SVE 算法優化相關介紹

SVE(Scalable Vector Extension) ARM AArch64 架構的下一代 SIMD 指令集。

  • 支持 SVE1 指令集。
  • 自動判斷適應 SVE1/NEON
  • 支持 Z0~Z31 寄存器。
  • 支持從 128~2048 bits 全尺寸 SVE 寄存器。
  • 支持 PO~P7 謂詞寄存器。
  • 支持大部分自動向量化(SuperWord)Node

5.2SVE 算法優化成果

VectorAPI 新增 Node 所有貢獻到上游社區,畢昇 JDK 目前暫未合入。到目前爲止,SVE一共向上遊社區提交了 11 patch,相關代碼超過 3000 行。

public static float sumReductionImplement(float[] a, float[] b, float[] c, float[] d, float total) {

               for (int i = 0; i < a.length; i++) {

                       d[i] = (a[i] * b[i]) + (a[i] * c[i]) + (b[i] * c[i]);

                       total += d[i];

               }

               return total;

        }

優化以後的 NEON 機器代碼以下圖所示:

優化以後的 SVE 機器代碼以下圖所示:

6、軟硬協同——鯤鵬 KAE 硬件加速

  • KAE(Kunpeng Accelerator Engine)是華爲鯤鵬服務器提供的硬件加速器,在鯤鵬芯片中有一個獨立的 I/O DIE 用於處理加解密功能。
  • 畢昇 JDK 提供了 KAEProvider,充分發揮硬件能力,應用只須要簡單的適配,無須代碼開發,便可使用鯤鵬服務器的硬件能力,提供應用的運行效率。
  • 在畢昇 JDK 最新的版本,發佈了 4 款加解密算法(AESDigestHMACRSA),在針對 Benchmark 的測試中,部分算法能夠加速 40%,在安全領域將大大節約運行時間。目前和寶蘭德正在進行聯合開發。第二批算法的支持將於 Q2 發佈。
  • 加解密方案是基於 JCA(Java Cryptography ArchitectureJava 加密架構),是 Java 平臺的重要組成部分。KAE 是基於 JCA 來提供加解密服務,在畢昇 JDK 中稱爲 KAEProvider。流程以下圖所示:

  • JCA 提供 2 種方式選擇不一樣的 provider,經過代碼指定或者配置文件。以下:
  • 方式 1:使用 Security API 添加 KAE Provider,並設置其優先級。
  • 方式 2:修改 jre/lib/security/java.security 文件,添加 KAE Provider,並設置其優先級。

7、畢昇 JDK 還能帶來什麼價值?

  • 通過評估和測試,畢昇 JDK 目前還以社區的特性爲基礎 Backport 了一批有價值的特性。
  • G1 NUMAAware,該特性能充分發揮 NUMA 的優點,在多核的硬件平臺中效果更佳。畢昇 JDK 中還在社區的基礎上修復了一些問題:例如由於操做系統的線程調度致使線程在多個節點遷移,遷移在 NUMA 特性上會致使一些內存分區沒法獲得有效回收;加強了大對象的 NUMAAware 功能。效果提高以下圖所示:

  • JDK 10 AppCDS 的特性,其思路是將 String 對象,類元數據對象存放到一個共享文件中,讓多個 JVM 進程可以經過共享信息,減小類元數據對象的加載、解析。
  • 畢昇 JDK 經過移植該特性,測試發現取得良好的效果,對於大數據的一些場景能夠優化接近 10%
  • G1 Uncommit,在內存使用較低的狀況下,會經過週期性的觸發 GC 進行垃圾回收,並將回收後的內存歸還給操做系統,該特性對於雲場景中,能明顯的下降內存的私有量。畢昇 JDK 在社區版本基礎上,將串行的內存釋放修改成併發(在最新的 JDK 16 中也採用了相同的實現)

在開啓 G1 Uncommit 後,咱們能夠在下圖中看到,在內存不使用的場景中會穩步降低:


而在實際的業務場景中,效果更是顯而易見的,以下圖所示:

  • 並行任務竊取機制優化,在一些應用發現任務竊取佔比很高。對於並行任務竊取 Google 對社區貢獻了一個有價值的設計,極大的優化了並行任務竊取。在畢昇 JDK 中,PSParNewG1Shenandoah 等都所以而受益。

  • 目前咱們正在針對多核的服務器優化任務竊取,待成熟後會繼續開源。

8、畢昇 JDK 的將來發展

8.1、即將面世的功能

  • 完善 KAE 硬件加速算法,預計 Q2 發佈。
  • G1 GC 中並行 NUMA-AwareFull GC 將落地於畢昇 JDK8Q2
  • jmap 加強,針對 CMS 作並行 dump

8.2、將來方向

  • 積極參與社區中 SVEVector API 特性的開發、演進。目前提交代碼超 3000 行。
  • 優化內存管理,正在進行:ZGC 分代、Thread Local GCAOT 等項目。

9、如何得到畢昇 JDK 及幫助?

下載 JDK 8 JDK 11https://kunpeng.huawei.com/#/developer/devkit/complier?data=JDK

9.1JDK 8 的代碼倉

https://gitee.com/openeuler/bishengjdk-8

9.2JDK 11 的代碼倉

https://gitee.com/openeuler/bishengjdk-11


總結

本文咱們給你們介紹了何爲畢昇 JDK,總體的發展史如何,是在什麼樣的形勢下華爲要作畢昇 JDK,在底層的優化方面又作到了哪些?同時又潛藏了哪些值得開發的價值?正如華爲編譯器資深技術專家彭成寒老師所講,把數字世界帶入每一個人、每一個家庭、每一個組織,構建萬物互聯的智能世界,這是咱們的追求!

 

點擊關注,第一時間瞭解華爲雲新鮮技術~

相關文章
相關標籤/搜索