Java SE 10 Application Class-Data Sharing 示例
Java SE 10 Application Class-Data Sharing 示例
作者:Grey
原文地址:Java SE 10 Application Class-Data Sharing 示例
Class-Data Sharing
CDS 全稱 Class-Data Sharing。主要是用來在不同的 JVM 中共享 Class-Data 信息,從而提升應用程序的啟動速度。
通常來說,如果要執行 class 位元組碼,JVM需要執行下面的一些步驟:給定一個類的名字,JVM 需要從磁盤上面找到這個文件,加載,並驗證位元組碼,最後將它加載進來。如果 JVM 啟動的時候需要加載成百上千個 class ,那麼需要的就不是一個小數目了。
對於打包好的 jar 包來說,只要 jar 的內容不變,那麼 jar 包中的類的數據始終是相同的。JVM 在啟動時候每次都會運行相同的加載步驟。CDS 的作用就是將這些能夠共享的數據歸類成一個存儲文件,在不同的 JVM 中共享。這樣可以實現兩個目標:
- 縮短JVM的啟動時間。
- 減少JVM的內存佔用。
當 JVM 啟動時,它從文件系統中加載 JDK 類庫(到JDK 8為止,從jre/lib/rt.jar
文件;從JDK 9開始,從jmods
目錄下的jmod
文件)。在這個過程中,類文件被從檔案中提取出來,轉換為特定架構的二進制形式,並存儲在JVM進程的主內存中。
如果在同一台機器上啟動了多個JVM,這個過程會重複進行。每個 JVM 在內存中保留其類庫的副本。
CDS 的工作原理如下。
- 使用
-Xshare:dump
命令,創建一個叫做classes.jsa
的文件(JSA 代表 Java Shared Archive)。這個文件包含了當前架構下的二進制格式的完整類庫。 - 當 JVM 啟動時,操作系統使用 內存映射 I/O將該文件 “映射 “到 JVM 的內存中。首先,這比加載 jar 或 jmod 文件要快。其次,操作系統只將文件加載到 RAM 中一次,為每個 JVM 進程提供同一內存區域的只讀視圖。
Application Class-Data Sharing
Application Class-Data Sharing 擴展了 CDS,不僅可以將 JDK 類庫,還可以將應用程序的類存儲在 JSA 文件中,並在 JVM 進程中共享。
以下示例代碼演示了App CDS 的功能。
規劃項目目錄
hello-cds
- src
- git
- snippets
- cds
- App.java
- Helper.java
Java 版本需要使用 JDK 10。
代碼清單
App.java
package git.snippets.cds;
public class App {
public static void main(String[] args) {
new Helper().greet();
}
}
Helper.java
package git.snippets.cds;
public class Helper {
public void greet() {
System.out.println("Hello world!");
}
}
接下來在hello-cds
根目錄下新建target
目錄,並運行如下命令進行編譯
javac -d target/classes src/git/snippets/cds/*.java
打包
jar cf target/helloworld.jar -C target/classes .
運行
java -cp target/helloworld.jar git.snippets.cds.App
可以看到控制台打印
Hello world!
接下來開始使用 Application CDS , 我們通過如下命令創建一個helloworld.lst
java -Xshare:off -XX:+UseAppCDS -XX:DumpLoadedClassList=helloworld.lst -cp target/helloworld.jar git.snippets.cds.App
注意。此命令僅在 OpenJDK 中有效。在 Oracle JDK 中,你會得到一個警告,說 Application CDS 是一個商業特性,你必須先解鎖(用-XX:+UnlockCommercialFeatures
)。所以最好使用 OpenJDK,且 JDK 版本必須是10。如果你使用Oracle JDK
,用如下命令代替
java -XX:+UnlockCommercialFeatures -Xshare:off -XX:+UseAppCDS -XX:DumpLoadedClassList=helloworld.lst -cp target/helloworld.jar git.snippets.cds.App
可以用記事本打開 helloworld.lst
,發現裏面包括了所有相關的class
清單,這裏面不僅有 JDK 的 class,也有應用程序的 class。
java/lang/Object
java/lang/String
java/io/Serializable
java/lang/Comparable
java/lang/CharSequence
java/lang/Class
....
git/snippets/cds/App
java/lang/PublicMethods$MethodList
java/lang/PublicMethods$Key
git/snippets/cds/Helper
java/lang/Shutdown
java/lang/Shutdown$Lock
接下來,我們通過 lst 問題創建 JSA 文件,
如果使用OpenJDK 10
,則用如下命令
java -Xshare:dump -XX:+UseAppCDS -XX:SharedClassListFile=helloworld.lst -XX:SharedArchiveFile=helloworld.jsa -cp target/helloworld.jar
如果使用Oracle JDK 10
,使用如下命令
java -Xshare:dump -XX:+UnlockCommercialFeatures -XX:+UseAppCDS -XX:SharedClassListFile=helloworld.lst -XX:SharedArchiveFile=helloworld.jsa -cp target/helloworld.jar
控制台輸出如下信息
narrow_klass_base = 0x0000000800000000, narrow_klass_shift = 3
Allocated temporary class space: 1073741824 bytes at 0x00000008c0000000
Allocated shared space: 3221225472 bytes at 0x0000000800000000
Loading classes to share ...
Loading classes to share: done.
Rewriting and linking classes ...
Rewriting and linking classes: done
Number of classes 689
instance classes = 609
obj array classes = 72
type array classes = 8
Updating ConstMethods ... done.
Removing unshareable information ... done.
Scanning all metaspace objects ...
Allocating RW objects ...
Allocating RO objects ...
Relocating embedded pointers ...
Relocating external roots ...
Dumping symbol table ...
Relocating SystemDictionary::_well_known_klasses[] ...
Removing java_mirror ... done.
mc space: 5656 [ 0.1% of total] out of 65536 bytes [ 8.6% used] at 0x0000000800000000
rw space: 2079360 [ 21.4% of total] out of 2097152 bytes [ 99.2% used] at 0x0000000800010000
ro space: 3934688 [ 40.6% of total] out of 3997696 bytes [ 98.4% used] at 0x0000000800210000
md space: 6160 [ 0.1% of total] out of 65536 bytes [ 9.4% used] at 0x00000008005e0000
od space: 3413720 [ 35.2% of total] out of 3473408 bytes [ 98.3% used] at 0x00000008005f0000
total : 9439584 [100.0% of total] out of 9699328 bytes [ 97.3% used]
生成的 helloworld.jsa 文件僅 9.31 MB 大小
使用jsa
文件重新運行程序
如果使用OpenJDK 10
運行如下命令
java -Xshare:on -XX:+UseAppCDS -XX:SharedArchiveFile=helloworld.jsa -cp target/helloworld.jar git.snippets.cds.App
如果使用Oracle JDK 10
,運行如下命令
java -Xshare:on -XX:+UnlockCommercialFeatures -XX:+UseAppCDS -XX:SharedArchiveFile=helloworld.jsa -cp target/helloworld.jar git.snippets.cds.App
控制台輸出
Hello world!
源碼
參考文檔
Java 10 Features (with Examples)
JEP 310: Application Class-Data Sharing