エンターテイメント!!

遊戯王好きのJavaエンジニアのブログ。バーニングソウルを会得する特訓中。

Javaでカスタムランタイムを試す

きっかけ

JavaのAdvent Callenderでjigsawでカスタムランタイム作ってる記事を見て、そういえばまだやってないなって思ってやろうと決心した。

実験

実装

実験の流れ

  1. サンプルクラス作成&実行
  2. jarを作る
  3. 依存モジュールの調査
  4. 最小構成JRE作成
  5. 4で作成した環境で実行してみる。

環境

os

$sw_vers
ProductName:    Mac OS X
ProductVersion: 10.14.2
BuildVersion:   18C54

もう、mojaveです。
最初、 もじゃば と読んでしまった流派の人です。
モハベが正しいらしい。
海外では、ややこしい読み方をカッコいいと感じるのだろうか?
日本だと、無理矢理感のあるルビは、もうイタイの部類に入ってきたと思うが、世界は遅れているな。

ダークモードにしたくて、恐る恐る変えた。

java

$ java -version
openjdk version "11.0.1" 2018-10-16
OpenJDK Runtime Environment 18.9 (build 11.0.1+13)
OpenJDK 64-Bit Server VM 18.9 (build 11.0.1+13, mixed mode)

実験のたたき台クラス

簡単なサンプルクラスを作る

public class HelloSaga {
  public static void main(String[] args) {
    System.out.println("Hello Saga!");
  }
}

もう、佐賀が好きすぎて hello world じゃなくて hello Saga にしないと気が済まない。
worldより偉大なSagaであります。

コンパイル実行

$ javac HelloSaga.java
$ java HelloSaga
Hello Saga!

当然、動きますよね。

jarを作る

これから、いろいろやるための準備として、jarを作る。

jar --create --file hello.jar --main-class HelloSaga HelloSaga.class

当然、動きます。

$ java -jar hello.jar
Hello Saga!

依存関係を調べる

java9で入った、jdepsコマンドで、依存しているモジュール郡を調べる。

$jdeps --list-deps hello.jar
   java.base

System.out.println が標準クラスに属しているので、 java.base のみが出てくる。

--list-depsは、公式サイトの説明を見ると、モジュールの依存関係の他、JDKの内部API (参照される場合)のパッケージ名もリストします。 とある。
コマンドの説明が見たい場合は、jdeps -hで参照可能。

ちなみに、何もつけないで実行した場合、下記の表記になる。

$jdeps hello.jar
hello.jar -> java.base
   <unnamed>                                          -> java.io                                            java.base
   <unnamed>                                          -> java.lang                                          java.base

java.ioだけだと思ったら、Stringも使ってるから、java.langも入るのか。。。
ただ、どっちもjava.baseに入っているから、見たい情報が重複するので、依存モジュールを見たいときは、--list-deps をつけるのが良さそう。

小さなJREを作る

依存しているモジュールが、java.baseだけということがわかったので、java.baseのみのJREを作る。
JREを作るには、jlinkコマンドを使う。

jlink --compress=2 --module-path "{jdkのパス}/jmods" --add-modules java.base --output jre-min

自分は、なぜかjlinkの環境パスが通ってなかったので、フルパスを打って実行した。
jenvを使っているのだが、それがいろいろやっているんでしょ?的な感じがした。
本題とそれるので、スルー。
目的を見失うからな。

とりあえず、jlinkのコマンド説明。

jlink

参考サイトにもオプション説明はあるが、疑問符が浮かぶ箇所もあったので、改めて説明をまとめる。

引数 説明
--compress=2 圧縮オプション。2を指定するとzipで圧縮。0はなし、1は、定数の共有
--module-path jlinkツールで参照可能なモジュールを検出するパス。
--add-modules 追加するモジュール郡。複数指定可能。今回は、java.baseのみを使うので、ここに指定
–output 出力する場所

オプションを詳しく知りたい場合は、 jlinks -h で調べられる。

上記のJRE生成コマンドを実行した場合、jremin ディレクトリが作られる。

もとのJREのフォルダのサイズを調べたが、自分の環境では286Mあった。
生成したjreminは、26M。
java.baseしか使ってないからだが、かなり減った。

実行

何も入ってない環境にするのが億劫なので、手打ちで試す。

$jremin/bin/java -jar hello.jar
Hello Saga!

無事に動いた!
最悪、javaをインストールしてない環境でも、生成したJREとjarがあれば、動かせるってことですね。
これらをIoT端末に載せて動かそうってのが、意図だろう。
もしかすると、末端の部品は、更に省メモリだから、エッジ端末くらいかもしれないが。
ハードのことは、よくわからんとです。
Androidが可能性として高そうな気がする。

考察

jdeps/jlinkといったツールが、かなり使える印象。
ある程度、ソフトウェアが育ってしまうと、モジュール分割したい要望が出てくるので、それを調査するのにも使えそう。
とういうか、モジュール分割をする作業をjavascriptでかなり苦戦してやっていたので、このツールのありがたみは、よく分かる。

初めてカスタムランタイムを作ったが、思ったよりあっさりできた。
もっと苦戦すると思ったんだがな。
環境周りの知識がついてきているおかげかも知れない。

参考サイト

アプリケーション配布用に小さなJREを作る

jdeps

jdeps

jlink