Javaの超低レイテンシなGCアルゴリズム、ZGCをコンパイルして動作を試す
The Z Garbage Collector
以下の資料を見てZGCのことを知りました。
ZGCは、 "A Scalable Low Latency Garbage Collector" というものだそうで、まだ開発中でリリースはされていないです。
数TBまでのヒープメモリのサイズを想定していて、なおかつGCの最大停止時間が10msというのがゴール。既にヒープサイズが128GBのベンチマークにおいて、パラレルGCやG1GCより圧倒的に停止時間が短い。ベンチマーク上では最大停止時間も10msを切っています。 アルゴリズムについては別途まとめてみようかと思っています。Colored Pointerという概念が特徴です。
ZGCを試す
開発版のZGCは既に試すことができるようです。ですが、自分でビルドする必要があります。紹介したスライドで書かれている方法ではうまくいかなかったのですが、なんとか動かすところまでできたので紹介します。
環境はUbuntu16.04.3で、24CPU、48GBメモリのサーバで作業しました。メモリは8GBもあればビルドできるのではないかと思います。
必要なパッケージをインストール
ubuntu@java-z:~$ sudo apt install build-essential mercurial zip unzip libx11-dev libxext-dev libxrender-dev libxtst-dev libxt-dev libcups2-dev libfontconfig1-dev libasound2-dev
ZGCプロジェクトのリポジトリをダウンロードしてくる
3GB以上あるので、そこそこ待たされます。
ubuntu@java-z:~$ hg clone http://hg.openjdk.java.net/zgc/zgc
configureする
ubuntu@java-z:~$ cd zgc ubuntu@java-z:~/zgc$ sh ./configure [...略] checking for javac... no checking for java... no configure: Could not find a valid Boot JDK. You might be able to fix this by running 'sudo apt-get install openjdk-8-jdk'. configure: This might be fixed by explicitly setting --with-boot-jdk configure: error: Cannot continue
openjdk-8-jdk
をインストールしろというメッセージが出ますが、実際に必要なのは JDK9
です。ここでOpenJDK 9をインストールしたくなりますが、後述する理由ビルドがコケます。
=== Output from failing command(s) repeated here === * For target buildtools_interim_langtools_modules_java.compiler.interim__the.BUILD_java.compiler.interim_batch: javac: invalid flag: --module-path Usage: javac <options> <source files> use -help for a list of possible options javac: no source files Usage: javac <options> <source files> use -help for a list of possible options
javacに --module-path
というオプションがないというエラーです。実はこれ、OpenJDKとOracle JDKでコマンドオプションの引数の名前が違うせいです。このまま通るようにするにはOracleのJDK9をインストールする必要があります。
ubuntu@java-z:~/zgc$ sh ./configure [...略] Configuration summary: * Debug level: release * HS debug level: product * JDK variant: normal * JVM variants: server * OpenJDK target: OS: linux, CPU architecture: x86, address length: 64 * Version string: 10-internal+0-adhoc.ubuntu.zgc (10-internal) Tools summary: * Boot JDK: openjdk version "9-internal" OpenJDK Runtime Environment (build 9-internal+0-2016-04-14-195246.buildd.src) OpenJDK 64-Bit Server VM (build 9-internal+0-2016-04-14-195246.buildd.src, mixed mode) (at /usr/lib/jvm/java-9-openjdk-amd64) * Toolchain: gcc (GNU Compiler Collection) * C Compiler: Version 5.4.0 (at /usr/bin/gcc) * C++ Compiler: Version 5.4.0 (at /usr/bin/g++) Build performance summary: * Cores to use: 24 * Memory limit: 48287 MB
うまくいくと、上記のような出力が出るはずです。
makeする
ubuntu@java-z:~/zgc$ make images
ビルドが終わるまで待ちます。自分の環境だと4分半くらいで終わりました。
CPUが全コアほぼ100%になった。
javaのバージョンの確認
ubuntu@java-z:~$ cd zgc/build/linux-x86_64-normal-server-release/images/jdk/bin ubuntu@java-z:~/zgc/build/linux-x86_64-normal-server-release/images/jdk/bin$ ./java -version openjdk version "10-internal" 2018-03-20 OpenJDK Runtime Environment (build 10-internal+0-adhoc.ubuntu.zgc) OpenJDK 64-Bit Server VM (build 10-internal+0-adhoc.ubuntu.zgc, mixed mode)
ZGC開発用のJava10がビルドされたのがわかります。
ZGCを使ってみる
100KB程度のオブジェクトを大量に生成するだけのプログラムを作りました。
import java.util.Arrays; class Data { byte[] data; Data() { byte[] array = new byte[100000]; Arrays.fill(array, (byte)1); this.data = array; } } public class Hello { public static void main(String[] args){ System.out.println("########## START ##########"); for(int i =0; i < 1000; i++) { new Data(); } System.out.println("########## END ##########"); } }
コンパイル
ubuntu@java-z:~$ zgc/build/linux-x86_64-normal-server-release/jdk/bin/javac Hello.java
実行
-XX:+UseZGC
をつけるとZGCが有効になります。-Xlog:gc*
で詳細なGCのログが出ます。 ヒープサイズを最大100MBまでに制限して実行してみましょう。
ubuntu@java-z:~$ zgc/build/linux-x86_64-normal-server-release/jdk/bin/java -Xmx100M -XX:+UseZGC -Xlog:gc* Hello [0.006s][info][gc,init] Initializing The Z Garbage Collector [0.006s][info][gc,init] Version: 10-internal+0-adhoc.ubuntu.zgc (release) [0.006s][info][gc,init] NUMA Support: Enabled [0.006s][info][gc,init] NUMA Nodes: 2 [0.006s][info][gc,init] CPUs: 24 total, 24 available [0.006s][info][gc,init] Memory: 48287M [0.006s][info][gc,init] Large Page Support: Disabled [0.006s][info][gc,init] Workers: 15 parallel, 3 concurrent [0.010s][info][gc,init] Pre-touching: Disabled [0.010s][info][gc,init] Pre-mapping: 100M [0.035s][info][gc ] Using The Z Garbage Collector [0.187s][info][gc,start] GC(0) Garbage Collection (Warmup) [略...] [0.483s][info][gc,ref ] GC(7) Clearing All Soft References [0.483s][info][gc,start ] GC(7) Garbage Collection (Allocation Stall) [0.483s][info][gc,phases ] GC(7) Pause Mark Start 0.141ms [0.485s][info][gc,phases ] GC(7) Concurrent Mark 2.015ms [0.486s][info][gc,phases ] GC(7) Pause Mark End 0.667ms [0.486s][info][gc,phases ] GC(7) Concurrent Process Non-Strong References 0.133ms [0.486s][info][gc,phases ] GC(7) Concurrent Reset Relocation Set 0.054ms [0.486s][info][gc,phases ] GC(7) Concurrent Destroy Detached Pages 0.001ms [0.486s][info][gc ] Allocation Stall (main) 3.605ms [0.490s][info][gc,phases ] GC(7) Concurrent Select Relocation Set 3.574ms [0.490s][info][gc,phases ] GC(7) Concurrent Prepare Relocation Set 0.289ms [0.491s][info][gc,phases ] GC(7) Pause Relocate Start 0.519ms [0.491s][info][gc ] Allocation Stall (main) 1.226ms [0.493s][info][gc,phases ] GC(7) Concurrent Relocate 1.953ms [0.493s][info][gc,load ] GC(7) Load: 0.61/0.70/0.51 [0.493s][info][gc,mmu ] GC(7) MMU: 2ms/16.2%, 5ms/52.6%, 10ms/75.0%, 20ms/84.0%, 50ms/88.6%, 100ms/93.2% [0.493s][info][gc,marking] GC(7) Mark: 8 stripe(s), 1 proactive flush(es), 1 terminate flush(es), 0 completion(s), 0 continuation(s) [0.493s][info][gc,reloc ] GC(7) Relocation: Successful, 1M relocated [0.493s][info][gc,nmethod] GC(7) NMethods: 128 registered, 0 unregistered [0.493s][info][gc,ref ] GC(7) Soft: 153 encountered, 19 discovered, 19 dropped, 0 enqueued [0.493s][info][gc,ref ] GC(7) Weak: 147 encountered, 78 discovered, 78 dropped, 0 enqueued [0.493s][info][gc,ref ] GC(7) Final: 0 encountered, 0 discovered, 0 dropped, 0 enqueued [0.493s][info][gc,ref ] GC(7) Phantom: 3 encountered, 3 discovered, 3 dropped, 0 enqueued [0.493s][info][gc,heap ] GC(7) Mark Start Mark End Relocate Start Relocate End High Low [0.493s][info][gc,heap ] GC(7) Capacity: 100M (100%) 100M (100%) 100M (100%) 100M (100%) 100M (100%) 100M (100%) [0.493s][info][gc,heap ] GC(7) Reserve: 62M (62%) 62M (62%) 62M (62%) 62M (62%) 44M (44%) 62M (62%) [0.493s][info][gc,heap ] GC(7) Free: 0M (0%) 0M (0%) 0M (0%) 0M (0%) 10M (10%) 0M (0%) [0.493s][info][gc,heap ] GC(7) Used: 38M (38%) 38M (38%) 38M (38%) 38M (38%) 56M (56%) 28M (28%) [0.493s][info][gc,heap ] GC(7) Live: - 1M (2%) 1M (2%) 1M (2%) - - [0.493s][info][gc,heap ] GC(7) Allocated: - 0M (0%) 12M (12%) 38M (38%) - - [0.493s][info][gc,heap ] GC(7) Garbage: - 36M (36%) 24M (24%) 16M (16%) - - [0.493s][info][gc,heap ] GC(7) Reclaimed: - - 12M (12%) 20M (20%) - - [0.493s][info][gc ] GC(7) Garbage Collection (Allocation Stall) 38M(38%)->38M(38%) [略...] [0.528s][info][gc,heap,exit] Heap [0.528s][info][gc,heap,exit] ZHeap used 30M, capacity 100M, max capacity 100M [0.528s][info][gc,heap,exit] Metaspace used 6395K, capacity 6442K, committed 6656K, reserved 8192K