Java 10 新特性之 AppCDS

khotyn同學發表於2018-03-21

Oracle 昨天公佈了 Java 10 的 GA 版本,Java 10 裡面除了本地變數型別推斷之外,還擴充套件了原來的 CDS 的能力為 AppCDS

什麼是 CDS

CDS 的全稱是 Class-Data Sharing,CDS 的作用是可以讓類可以被預處理放到一個歸檔檔案中,後續 Java 程式啟動的時候可以直接帶上這個歸檔檔案,這樣 JVM 可以直接將這個歸檔檔案對映到記憶體中,以節約應用啟動的時間。

這個特性其實 JDK 1.5 就開始引入了,但是 CDS 只能作用與 Boot Class Loader 載入的類,不能作用於 App Class Loader 或者自定義的 Class Loader 載入的類,其實有點雞肋,而且這個是 Oracle JDK 的商業特性,在 OpenJDK 中似乎沒有。

這次在 Java 10 中,則將 CDS 擴充套件為 AppCDS,顧名思義,AppCDS 不止能夠作用於 Boot Class Loader,App Class Loader 和自定義的 Class Loader 也都能夠起作用,大大加大了 CDS 的適用範圍。有了 AppCDS,可以給 Java 的應用程式帶來兩個方面的好處:

  • 可以提升一些大型的 Java 應用的啟動速度。
  • 可以提升 Serverless 的應用程式的啟動速度。我覺得這個點可能是 Java 10 提供 AppCDS 的主要原因,Serverless 極可能成為未來的應用的一種非常常見的形態,而把 Java 應用在 Serverless 上,相比於其他的語言來說,一個很大的劣勢就是 JVM 的啟動速度太慢了,雖然像 AWS 的 Lambda,會給 Java 的 Serverless 應用加上 -client 來用 Client 模式跑加快啟動速度,但是實際上效果甚微。有了 AppCDS,可以大大加快 Serverless 應用的啟動速度,按照 AppCDS 的 JEP 的說明,對於一個 JEdit 來說,AppCDS 可以為 JEdit 提升 20% 到 30% 的啟動速度。

嘗試 AppCDS

作者寫了一個簡單的 Java 應用,來測試 AppCDS 的效果。程式的程式碼已經放到了 Github 上面,大家可以直接去看,這裡只給出大概的操作步驟和最後的測試效果。

1. 決定要 Dump 哪些 Class

一般來說,一個 Java 應用程式會包含很多的 Class 檔案,但是在執行中,並不是所有的 Class 檔案都會被用到,所以,第一步我們需要來決定具體需要使用哪些 Class 檔案,你需要給你的執行命令上加上如下的 JVM 引數:

-Xshare:off -XX:+UseAppCDS -XX:DumpLoadedClassList=hello.lst
複製程式碼

幾個引數的意思分別是:

  • -Xshare:off:這個引數的意思是不做任何記憶體的共享,也就是不利用 AppCDS 產生的檔案來做記憶體對映。因為是要決定 Dump 哪些類的記憶體到歸檔檔案中,所以這個引數需要關掉。
  • -XX:+UserAppCDS:預設的情況下 AppCDS 不會開啟,所以我們需要加上這個引數來開啟 AppCDS。
  • -XX:DumpLoadedClassList:表示需要把需要做 Dump 的類名寫入到哪個檔案中。

這個命令執行之後,會出現一個 hello.lst 的檔案,裡面就是一個個的類名,下面是一部分內容的截圖:

Java 10 新特性之 AppCDS

2. 將類的記憶體 Dump 到歸檔檔案中

有一個需要 Dump 的類的列表之後,第二步,我們就可以將類的記憶體 Dump 到歸檔檔案中了,在這一步中,我們需要將以下的引數加入到 JVM 引數中去:

-Xshare:dump -XX:+UseAppCDS -XX:SharedClassListFile=hello.lst -XX:SharedArchiveFile=hello.jsa
複製程式碼

幾個引數的含義分別如下:

  • -Xshare:dump:表示現在要進行類的記憶體的 Dump。
  • -XX:SharedClassListFile:用來指定需要 Dump 的類的列表。
  • -XX:SharedArchiveFile:表示需要將類的記憶體 Dump 到哪個歸檔檔案中。

執行上面的命令之後,我們會得到一個 hello.jsa 的檔案,包含需要的記憶體資訊的 Dump。

3. 使用 Dump 出來的歸檔檔案加快應用啟動速度

有了前面的歸檔檔案之後,我們就可以來加速應用的啟動速度了,為了使用上述的歸檔檔案,我們需要在 JVM 中加上如下的引數:

-Xshare:on -XX:+UseAppCDS -XX:SharedArchiveFile=hello.jsa
複製程式碼

幾個引數的含義分別如下:

  • -Xshare:on:表示開啟記憶體對映。
  • -XX:SharedArchiveFile=hello.jsa:表示用來做記憶體對映的歸檔檔案是 hello.jsa

4. 測試效果

在我的本機上,不使用 AppCDS 和使用 AppCDS 的效果如下:

不使用 AppCDS

Java 10 新特性之 AppCDS

使用 AppCDS

Java 10 新特性之 AppCDS
可以看到,對於這樣一個簡單的應用,AppCDS 還是有 20% 左右的啟動速度提升的,當然這個應用的很多的啟動時間都花在了類載入上,其他的耗時不多,所以效果挺好。如果其他的應用程式的啟動時間花在類上的載入時間比較少的話,可能效果就沒有這麼明顯。

看起來 AppCDS 很美好,但是目前我使用下來有幾個坑:

  • 雖然 AppCDS 號稱可以支援自定義的 ClassLoader,但是我試了一個 SpringBoot 的應用,發現對於沒有在 -classpath 中指定的 JAR 包中的類,並不會有效果。
  • 如果你下載 Oracle 的 JDK,需要加上 -XX:+UnlockCommercialFeature 來開啟 AppCDS,但是 OpenJDK 卻不用,也是很奇怪,?

相關文章