Huawei系Android端末のアプリ内の地図で "google play services are updating" という表示が出たまま地図が表示されない件

Huawei Mate 9を使ってるのですが、気がついたらアプリ内に地図が表示されなくなっていて、代わりに "google play services are updating" という一文だけが表示されていました。P 10, P10 liteでも発生したという話も見かけます。

https://lh3.googleusercontent.com/-wmHAml1-Hs0/Wpy33EYUoVI/AAAAAAAAACc/TACEu7GB1ekDdij-5zcFQ2JB0ZiDEMNtwCL4CGAYYCw/s1600/S80305-105955.jpg ( https://productforums.google.com/forum/#!topic/play/xfLz_9emKs0 より)

対処方法

https://productforums.google.com/forum/#!topic/play/xfLz_9emKs0 ここのフォーラムで議論されている内容が近そうです。 自分の端末の場合は以下のような対応で治りました。

設定 → アプリと通知 → アプリ → Google Play開発者サービス → 無効にする → "google play services are updating" が出ていたアプリを開く → Google Play開発者サービスを更新するか聞かれる → 更新する → 地図が問題なく表示されるようになる

サイトブロッキングが話題なのでDNSブロッキングを実現するための方法を検証してみた

本日、NTTコミュニケーションズ、NTTドコモ、NTTぷららの3社はサイトブロッキングを実施するとの方針を発表しましたね。

www.ntt.com https://www.asahi.com/articles/ASL4R4Q81L4RULFA01G.htmlwww.asahi.com

技術的にはどのように実現すればよいのか興味があるので検証してみました。

サイトブロッキングを実現するための方法の一つとして、「DNSブロッキング」という手法があるそうです。ISPがユーザに対して提供しているDNSキャッシュサーバでブロックしたいサイトの名前解決をできないようにする手法です。ただこの手法を用いても、ユーザがISPの管理外の 1.1.1.1, 1.0.0.1, 8.8.8.8, 8.8.4.4 のようなpublic DNS serverを使えば回避できてしまうのであまり意味はありません。

DNSブロッキングに対応したDNSサーバを構築する

今回はOSとしてubuntu16.04の上でDNSキャッシュリゾルバであるunboundを構築して設定していきます。

まずはふつうのDNSフルリゾルバを構築する

まずはユーザに提供するようのDNSフルリゾルバを作成します。 aptコマンドを使ってunboundをインストールします。

ubuntu@dns-resolver01:~$ sudo apt install unbound

ubuntu@dns-resolver01:~$ sudo service unbound status
● unbound.service
   Loaded: loaded (/etc/init.d/unbound; bad; vendor preset: enabled)
  Drop-In: /run/systemd/generator/unbound.service.d
           └─50-insserv.conf-$named.conf, 50-unbound-$named.conf
   Active: active (running) since Mon 2018-04-23 06:57:24 UTC; 17min ago
     Docs: man:systemd-sysv-generator(8)
   CGroup: /system.slice/unbound.service
           └─2297 /usr/sbin/unbound

インストールコマンドを1行打つだけでunboundがインストールされて起動されていることがわかりますね。この状態だと外部からのアクセスに応答しないようになっているので、private IP アドレスからの問い合わせには応答するようにしてみましょう。

/etc/unbound/unbound.conf.d/dns-cache.conf というファイルを作成し、以下の内容を記述します。

server:
    interface: 0.0.0.0
    access-control: 10.0.0.0/8 allow
    access-control: 172.16.0.0/12 allow
    access-control: 192.168.0.0/16 allow
    access-control: 127.0.0.1/32 allow

完了したら、以下のコマンドで再起動をします。

ubuntu@dns-resolver01:~$ sudo service unbound restart

これで別のホストからのアクセスにも応答できるはずです。別ホストからDNSサーバとして参照してみた時の結果が以下です。 10.55.48.99 というのは今回構築したサーバのIPアドレスです。

ubuntu@ubuntu01:~$ dig +short google.com @10.55.48.99
216.58.197.174

DNSによるサイトブロッキングを実現する

ここからが本題です。特定のサイトへアクセスできないようにするにはどうすればよいのでしょうか。サイトブロッキングの対象とされている anitube.se にアクセスできないようにしてみましょう。まずは特に設定を入れない状態で anitube.se の名前解決をしてみます。

ubuntu@ubuntu01:~$ dig +short anitube.se
104.20.203.27
104.20.202.27

2つのIPアドレスが返ってきましたね。名前解決ができています。これを解決できないようにしたいということです。

Unboundのpython拡張

Unboundにはpythonスクリプトで拡張をする機能があります。ドキュメントを参考にして実装しました。 https://unbound.net/documentation/pythonmod/examples/example0.html

gist.github.com

def filter_domain(qstate, id):
    domain = qstate.qinfo.qname_str.rstrip('.')
    if domain in block_domains:
        qstate.return_rcode = RCODE_NXDOMAIN
        qstate.ext_state[id] = MODULE_FINISHED
    else:
        qstate.ext_state[id] = MODULE_WAIT_MODULE

filter_domainという箇所でクエリで問い合わせられているドメインがブラックリストに入っていれば名前解決を続行せずに NXDOMAIN を即答するようになっています。

このスクリプトを /etc/unbound/unbound/domain_filter.py に設置します。

Unboundの設定

UnboundのPython拡張をインストールします。

ubuntu@dns-resolver01:~$ sudo apt install python-unbound

/etc/unbound/unbound.conf.d/dns-cache.conf を以下のように書き換えます。

server:
    interface: 0.0.0.0
    access-control: 10.0.0.0/8 allow
    access-control: 172.16.0.0/12 allow
    access-control: 192.168.0.0/16 allow
    access-control: 127.0.0.1/32 allow
    module-config: "python validator iterator"
python:
    python-script: "/etc/unbound/domain_filter.py"

ドメインのフィルタ対象の一覧ファイルを /etc/unbound/block_domains.txt に作成します。1行1ドメインで列挙していきます。

anitube.se

unboundを再起動します。

ubuntu@dns-resolver01:~$ sudo service unbound restart

動作確認

ubuntu@ubuntu01:~$ dig anitube.se @10.55.48.99

; <<>> DiG 9.10.3-P4-Ubuntu <<>> anitube.se @10.55.48.99
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 17521
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;anitube.se.                    IN      A

;; Query time: 0 msec
;; SERVER: 10.55.48.99#53(10.55.48.99)
;; WHEN: Mon Apr 23 10:01:15 UTC 2018
;; MSG SIZE  rcvd: 39

anitube.se を名前解決しようとしてもレコードが返ってこなくなりました。 ログを見るかぎり、結果はキャッシュされているようなので毎回実行されるわけではなさそうです。

追記

BINDだとRPZという機能を使えばDNSブロッキングができるらしい。職場の方に教えてもらいました。

sbt 1.x 系にアップグレードしたらCIでコンパイルキャッシュが効かなくなったので対処した

業務で開発しているプロジェクトで、sbtを0.13.17 から 1.1.1にアップグレードして喜んでいたらCIでキャッシュが効かなくなってしまい、ビルド時間が遅くなるという事象を経験したのでどのような調査をしたのかと、対処方法を書きます。ちなみにCIはCircleCI2.0を使っています。

コンパイルキャッシュが効かなくなる現象の確認

プロジェクトの作成

環境を用意します。Ubuntu16.04上にsbtをインストールしました。手順は以下のものを参考にしました。

sbt Reference Manual — Linux への sbt のインストール

hello と出力するだけのプロジェクトをつくります。 scala/scala-seed.g8 のテンプレートを使いました。

ubuntu@c01:~$ sbt new scala/scala-seed.g8
[info] Set current project to ubuntu (in build file:/home/ubuntu/)

A minimal Scala project.

name [Scala Seed Project]: hello-world

Template applied in ./hello-world

コンパイルと実行

動作確認をします。 sbt run を2度実行しています。

ubuntu@c01:~$ cd hello-world/
ubuntu@c01:~/hello-world$ sbt run
[info] Loading project definition from /home/ubuntu/hello-world/project
[info] Updating ProjectRef(uri("file:/home/ubuntu/hello-world/project/"), "hello-world-build")...
[info] Done updating.
[info] Compiling 1 Scala source to /home/ubuntu/hello-world/project/target/scala-2.12/sbt-1.0/classes ...
[info] Done compiling.
[info] Loading settings from build.sbt ...
[info] Set current project to hello-world (in build file:/home/ubuntu/hello-world/)
[info] Updating ...
[info] Done updating.
[info] Compiling 1 Scala source to /home/ubuntu/hello-world/target/scala-2.12/classes ...
[info] Done compiling.
[info] Packaging /home/ubuntu/hello-world/target/scala-2.12/hello-world_2.12-0.1.0-SNAPSHOT.jar ...
[info] Done packaging.
[info] Running example.Hello
hello
[success] Total time: 1 s, completed Mar 21, 2018 6:38:59 AM

ubuntu@c01:~/hello-world$ sbt run
[info] Loading project definition from /home/ubuntu/hello-world/project
[info] Loading settings from build.sbt ...
[info] Set current project to hello-world (in build file:/home/ubuntu/hello-world/)
[info] Packaging /home/ubuntu/hello-world/target/scala-2.12/hello-world_2.12-0.1.0-SNAPSHOT.jar ...
[info] Done packaging.
[info] Running example.Hello
hello
[success] Total time: 0 s, completed Mar 21, 2018 6:39:17 AM

1度目はコンパイルが走っていて、2度目はコンパイルキャッシュが効いているため、コンパイルを行わずに実行されていることがわかります。

CI上で行われているのと同様にコンパイルキャッシュの保存/展開操作を行う

CI上で行う操作は、

  1. ソースコードのチェックアウト
  2. (キャッシュがあれば)キャッシュの展開
  3. コンパイル・テスト
  4. キャッシュの作成・保存

です。

CI上の環境と同じ事を行ってみましょう。ソースコードはチェックアウトされたとみなして、初回のテストなのでキャッシュは存在しません。なので3のコンパイル・テストの工程からはじめます。

コンパイル・テスト

ubuntu@c01:~/hello-world$ sbt test
[info] Loading project definition from /home/ubuntu/hello-world/project
[info] Loading settings from build.sbt ...
[info] Set current project to hello-world (in build file:/home/ubuntu/hello-world/)
[info] HelloSpec:
[info] The Hello object
[info] - should say hello
[info] Run completed in 567 milliseconds.
[info] Total number of tests run: 1
[info] Suites: completed 1, aborted 0
[info] Tests: succeeded 1, failed 0, canceled 0, ignored 0, pending 0
[info] All tests passed.
[success] Total time: 1 s, completed Mar 21, 2018 6:52:09 AM

先程実行した時のコンパイルキャッシュが残っているのでコンパイルは走っていませんね。テストもきちんとパスしました。

キャッシュの作成・保存

tarコマンドを使って、 target ディレクトリ以下を1つのアーカイブにまとめます。

その他にも実際のCIでは ~/.sbt~/.ivy2 といったディレクトリもキャッシュされるようにする必要があります。今回はこの2つのディレクトリは問題の事象に関係がなかったので target ディレクトリだけを対象にします。

ubuntu@c01:~/hello-world$ tar cvf cache.tar target/
target/
target/streams/
target/streams/$global/
target/streams/$global/dependencyPositions/
target/streams/$global/dependencyPositions/$global/
[... 以下略]
target/scala-2.12/hello-world_2.12-0.1.0-SNAPSHOT.jar

実際のCIであれば、生成された cache.tar ファイルを保存して、次回のビルド時にこのファイルを展開してあげればコンパイルキャッシュが効くはず…です。

キャッシュの展開

先程生成したキャッシュを展開してみます。tarでアーカイブしたものをそのまま展開して上書きしただけなので特に変わりはないはずです。

ubuntu@c01:~/hello-world$ ls
build.sbt  cache.tar  project  src  target

ubuntu@c01:~/hello-world$ tar xvf cache.tar
target/
target/streams/
target/streams/$global/
target/streams/$global/dependencyPositions/
target/streams/$global/dependencyPositions/$global/
[...以下略]
target/scala-2.12/hello-world_2.12-0.1.0-SNAPSHOT.jar

再びテスト実行

再びテストを実行させてみます。

ubuntu@c01:~/hello-world$ sbt test
[info] Loading project definition from /home/ubuntu/hello-world/project
[info] Loading settings from build.sbt ...
[info] Set current project to hello-world (in build file:/home/ubuntu/hello-world/)
[info] Updating ...
[info] Done updating.
[info] Compiling 1 Scala source to /home/ubuntu/hello-world/target/scala-2.12/classes ...
[info] Done compiling.
[info] Compiling 1 Scala source to /home/ubuntu/hello-world/target/scala-2.12/test-classes ...
[info] Done compiling.
[info] HelloSpec:
[info] The Hello object
[info] - should say hello
[info] Run completed in 640 milliseconds.
[info] Total number of tests run: 1
[info] Suites: completed 1, aborted 0
[info] Tests: succeeded 1, failed 0, canceled 0, ignored 0, pending 0
[info] All tests passed.
[success] Total time: 7 s, completed Mar 21, 2018 7:04:58 AM

なんと、コンパイルが再び走ってしまっています。キャッシュが効いていないということですね。sbt0.13.17を使っていたときはこのやり方でうまくいっていたのですが…。

原因

どのディレクトリをtarでアーカイブしてからリストアするとこの事象が発生するのか、 target ディレクトリ以下を順番に掘り下げて行って調査したところ、 target/scala-2.12/resolution-cache/com.example/hello-world_2.12/0.1.0-SNAPSHOTディレクトリ以下のファイルが影響しているということがわかりました。

ubuntu@c01:~/hello-world/target/scala-2.12/resolution-cache/com.example/hello-world_2.12/0.1.0-SNAPSHOT$ ls -l
total 3
-rw-rw-r-- 1 ubuntu ubuntu  647 Mar 21 07:04 resolved.xml.properties
-rw-rw-r-- 1 ubuntu ubuntu 1943 Mar 21 07:04 resolved.xml.xml

このディレクトリにはファイルが2つあります。アーカイブなのでファイルの中身が変わるはずはありませんが、一応md5ハッシュの値を展開前と展開後で比べてみます。

# 展開前
ubuntu@c01:~/hello-world/target/scala-2.12/resolution-cache/com.example/hello-world_2.12/0.1.0-SNAPSHOT$ md5sum resolved.xml.*
d369e9bf8b52bddc7da2f93e58b6b86f  resolved.xml.properties
2c8964010ef6a2835dce1c3f2cc8853d  resolved.xml.xml

# 展開後
ubuntu@c01:~/hello-world/target/scala-2.12/resolution-cache/com.example/hello-world_2.12/0.1.0-SNAPSHOT$ md5sum resolved.xml.*
d369e9bf8b52bddc7da2f93e58b6b86f  resolved.xml.properties
2c8964010ef6a2835dce1c3f2cc8853d  resolved.xml.xml

当たり前ですが、ハッシュ値は一致しています。

もう一点疑う余地があるとすれば、タイムスタンプです。

# 展開前
ubuntu@c01:~/hello-world/target/scala-2.12/resolution-cache/com.example/hello-world_2.12/0.1.0-SNAPSHOT$ ls -l
total 3
-rw-rw-r-- 1 ubuntu ubuntu  647 Mar 21 07:04 resolved.xml.properties
-rw-rw-r-- 1 ubuntu ubuntu 1943 Mar 21 07:04 resolved.xml.xml

# 展開後
ubuntu@c01:~/hello-world/target/scala-2.12/resolution-cache/com.example/hello-world_2.12/0.1.0-SNAPSHOT$ ls -l
total 3
-rw-rw-r-- 1 ubuntu ubuntu  647 Mar 21 07:04 resolved.xml.properties
-rw-rw-r-- 1 ubuntu ubuntu 1943 Mar 21 07:04 resolved.xml.xml

特に変わりはないように思えますね…。ここでファイル作成時刻のタイムスタンプはもっと詳細な粒度で保持しているはず、という事を思い出しました。 ls コマンドの --full-time オプションで表示ができるようです。

# 展開前
ubuntu@c01:~/hello-world/target/scala-2.12/resolution-cache/com.example/hello-world_2.12/0.1.0-SNAPSHOT$ ls -l --full-time
total 3
-rw-rw-r-- 1 ubuntu ubuntu   647 2018-03-21 07:04:52.724370184 +0000 resolved.xml.properties
-rw-rw-r-- 1 ubuntu ubuntu  1943 2018-03-21 07:04:52.716369762 +0000 resolved.xml.xml

# 展開後
ubuntu@c01:~/hello-world/target/scala-2.12/resolution-cache/com.example/hello-world_2.12/0.1.0-SNAPSHOT$ ls -l --full-time
total 3
-rw-rw-r-- 1 ubuntu ubuntu  647 2018-03-21 07:04:52.000000000 +0000 resolved.xml.properties
-rw-rw-r-- 1 ubuntu ubuntu 1943 2018-03-21 07:04:52.000000000 +0000 resolved.xml.xml

おっと…!これですね。タイムスタンプが秒単位で丸められています。ここのタイムスタンプが完全に一致していないためにプロジェクトに変更が加えられたと認識されて、フルでコンパイルが走ってしまっているのではないかという当たりがつけられました。どうやらtarは標準ではファイルのタイムスタンプは秒未満は切り捨てるようです。zipは標準だと2秒単位でタイムスタンプを丸めるようです。

コンパイルキャッシュが効くようにするために対処した

社内でtarでアーカイブを作成するときにナノ秒単位でタイムスタンプを保持する方法がないか聞いたところ、以下のリンクを教えてもらいました。

unix.stackexchange.com

GNU tarを使っているときにposixフォーマットでアーカイブを作成するとよいということがわかりました。 --format posix をつけるとよいということですね。

再び実験

キャッシュを作ってからリストアする

ubuntu@c01:~/hello-world$ tar --format posix -cvf cache.tar target/
target/
target/streams/
target/streams/$global/
target/streams/$global/dependencyPositions/
target/streams/$global/dependencyPositions/$global/
[... 以下略]
target/scala-2.12/hello-world_2.12-0.1.0-SNAPSHOT.jar

ubuntu@c01:~/hello-world$ tar xvf cache.tar
target/
target/streams/
target/streams/$global/
target/streams/$global/dependencyPositions/
target/streams/$global/dependencyPositions/$global/
[...以下略]
target/scala-2.12/hello-world_2.12-0.1.0-SNAPSHOT.jar

テストを実行する

再びテストを実行してみます。

ubuntu@c01:~/hello-world$ sbt test
[info] Loading project definition from /home/ubuntu/hello-world/project
[info] Loading settings from build.sbt ...
[info] Set current project to hello-world (in build file:/home/ubuntu/hello-world/)
[info] Updating ...
[info] Done updating.
[info] HelloSpec:
[info] The Hello object
[info] - should say hello
[info] Run completed in 710 milliseconds.
[info] Total number of tests run: 1
[info] Suites: completed 1, aborted 0
[info] Tests: succeeded 1, failed 0, canceled 0, ignored 0, pending 0
[info] All tests passed.
[success] Total time: 2 s, completed Mar 21, 2018 7:25:45 AM

今度はちゃんとコンパイルキャッシュが効きました!これで安心してCIをたくさん回せます。

ちなみにCircleCI2.0の persist_to_workspace 機能を使っている時も同様な事象が起きますので、自前で上記の手法でtarアーカイブを作成してリストアするとよいでしょう。

まとめ

  • sbt 1.xではコンパイルキャッシュが使えるかどうかの判定にファイルのナノ秒単位のタイムスタンプを使っているように見える
  • sbt 1.xではコンパイルキャッシュ関連のファイルが作成されたタイムスタンプと、それがリストアされたときのタイムスタンプが完全に一致していないとコンパイルキャッシュが効かない
  • tar --format posix オプションでナノ秒単位のファイルのタイムスタンプが保存できる

Javaの超低レイテンシなGCアルゴリズム、ZGCをコンパイルして動作を試す

The Z Garbage Collector

以下の資料を見てZGCのことを知りました。

The Z Garbage Collector

ZGCは、 "A Scalable Low Latency Garbage Collector" というものだそうで、まだ開発中でリリースはされていないです。

f:id:kuro_m88:20180218013120p:plain

数TBまでのヒープメモリのサイズを想定していて、なおかつGCの最大停止時間が10msというのがゴール。既にヒープサイズが128GBのベンチマークにおいて、パラレルGCやG1GCより圧倒的に停止時間が短い。ベンチマーク上では最大停止時間も10msを切っています。 アルゴリズムについては別途まとめてみようかと思っています。Colored Pointerという概念が特徴です。

f:id:kuro_m88:20180218013454p:plain

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分半くらいで終わりました。

f:id:kuro_m88:20180225224416p:plain

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

こんな感じでGCのログが出ました。これでZGCをベンチマーク取ったりして試して遊べますね!