sbt-native-packagerでパッケージングしたアプリケーションのJVMオプションに-Jをつけるべきかどうか

普通に自分が分かってなかったのでメモシリーズ

これはなに

  • -Xmx オプションを指定する際に -J をつけている。 -Dfoo.barなどのプロパティ指定にはつけたりつけなかったりしている
  • いつ -J をつけて、いつつけなくてよいのか、 -J の意味などをまとめる。

-J の意味

-J の意味1 javaコマンドのオプションである -J

java -J” あたりでググるとコレがでてくる。 例: Javaアプリケーション メモ(Hishidama's Java-Application Memo)

これはjavacが使用するjavaコマンド(javacと同バージョンのjava)へのオプションを指定するものなので、Xmxの指定などの実行時のオプション設定には関係しない。

-J の意味2 jarコマンドのオプションである -J

こちらもググってみると、

たとえば、 -J-Xms48m と指定すると、スタートアップ・メモリーは48Mバイトに設定されます。

jar のように記載されている。

しかし「jarコマンド」はjarを作ったりjarの中身を一覧表示するためのコマンドであり、jarの実行(java -jar …)とは異なる物なのがポイントで、こちらもアプリケーション実行時に影響するオプションではない。

つまり jar -J-Xms48m はjarを作る作業中にjvmが使うメモリを変更するオプションであるという意味になる。

-J の意味3 scalaコマンド的な-J

scala -J-Xmx 2GB -Dfoo=bar baz.scala みたいにjavaコマンドではなくscalaコマンドでアプリケーションを実行するときのオプション

scalaコマンドは結局モロモロの処理をした後javaコマンドを実行するものになっている。

ここでのポイントは-Jオプションをscalaコマンドに渡すと以下の2つを行ってくれるということ

  • 渡された -J-Xmx1500m などの文字列をそのままjavaコマンドに渡す
  • -J を消した-Xmx1500mをscala引数として渡す

つまり -J の意味1 で述べたjavacうんぬんとは関係なく、scalaコマンドに -J を渡すとjava側に渡してくれる機能がある( -Jという名前が被っているので混乱するが、全然違う機能) scala/tool-unix.tmpl at c804289144c006e91a206ff12e94e5a39ac73a9f · scala/scala · GitHub

-J の意味4 sbt-native-packager的な -J

こちらはscalaコマンドに似ている。

sbt-native-packagerが生成するスクリプトはモロモロの処理をしてjavaコマンドを実行する。

このとき -J の意味2で述べたscalaコマンドの挙動を模した実装が行われており、scalaコマンドと同じように -J をstripして、 -Xmx 1500m にしてからjavaコマンドにわたすという形式になっている。

(scalaコマンドとは違いscala_argsには値が渡らない気がしているが未調査。気になる人は実装読んだりしてください)

sbt-native-packager/bash-template at master · sbt/sbt-native-packager · GitHub

-J をつけないとどうなるかというと sbt-native-packager/bash-template at 1ee84811c3ce2048e2ea857aece3fbe563b8089e · sbt/sbt-native-packager · GitHub によりresidual_argsに入り sbt-native-packager/bash-template at 1ee84811c3ce2048e2ea857aece3fbe563b8089e · sbt/sbt-native-packager · GitHub でmainClassやappCommandの後に引数として渡されるようです。

まとめ

sbt-native-packagerを使う場合、jvmオプションは -J-Xmx 1500m のようにする必要がある

これはscalaコマンドやsbt-native-packagerが独自実装しているshellスクリプトの機能でしかなく、jvmには-Jが削除された-Xmx 1500mだけが渡るようになっている。(-J-Xmxってなんか気持ち悪いなと思っていたけど-Jという文字列を機械的に削除すると考えれば割と理解しやすい)

この際使われる-J prefixはjavaコマンドについてググった時にでてくるjavacコマンドのオプションとは全く別物

おまけ

sbt-native-packagerを使う場合 -Dfoo=bar はそのままjvmに渡される (sbt-native-packager/bash-template at 1ee84811c3ce2048e2ea857aece3fbe563b8089e · sbt/sbt-native-packager · GitHub) ので、

例えばエンコーディング指定であれば -Dfile.encoding=UTF-8 とすればよい。

が、 -J-Dfile.encoding=UTF-8 としても -J機械的に削除されてjvmに渡るので結局 -Dfile.encoding=UTF-8となり、挙動はかわらない(はず)。