JavaCVを使って開発したアプリのJARファイルサイズを小さくする

JavaCVを使って画像処理のコードを書きました。作成したアプリをPaaSで動かしたかったので依存関係全部入りのfat JARを作ったのですが、大したアプリではないのにJARのファイルサイズがとても大きくなってしまったので、ファイルサイズの削減を試みます。

fat JARの作成方法から知りたい場合は↓の記事をご参照ください。

もともとのJARファイルサイズ

もともとのbuild.gradleには、JavaCVのREADMEにしたがって↓のように依存関係を記述していました。

GitHub - bytedeco/javacv: Java interface to OpenCV, FFmpeg, and more
Java interface to OpenCV, FFmpeg, and more. Contribute to bytedeco/javacv development by creating an account on GitHub.
dependencies {
    implementation group: 'org.bytedeco', name: 'javacv-platform', version: '1.5.6'
}

すると生成されたJARファイルのサイズは779Mとなり、とても大きいものになりました。

$ ls -lh build/libs/javacv_url_image_loader-1.0-SNAPSHOT-all.jar
-rw-r--r--  1 user  staff   779M Nov  7 07:17 build/libs/javacv_url_image_loader-1.0-SNAPSHOT-all.jar

こんなに大きいとPaaSへのデプロイに無駄に時間がかかってあれなので、JARファイルのサイズ削減してみました。

JARファイルのサイズ削減

今回はOpenCVをJavaで使いたくてJavaCVを利用しました。

JavaCVはOpenCV以外のライブラリも色々とラップしているので、方針としては使っていないライブラリは極力依存関係に含めないようにしたいと思います。

結論だけ先に書いておくと、おすすめは方法3です。

方法1:不要なライブラリを依存関係から除外するパターン

依存関係にjavacv-platformを単純に指定しただけではOpenCV以外の諸々のライブラリも含まれてしまうので、↓のように使っていないライブラリを明示的に指定して、依存関係に追加しないようにしてしまいます。

dependencies {
    implementation group: 'org.bytedeco', name: 'javacv-platform', version: '1.5.6', {
        exclude module: 'ffmpeg-platform'
        exclude module: 'flycapture-platform'
        exclude module: 'libdc1394-platform'
    }
}

とりあえず↑の3つだけ除外してJARファイルを作ってみると、ファイルサイズは606Mまで削減できました。

$ ls -lh build/libs/javacv_url_image_loader-1.0-SNAPSHOT-all.jar
-rw-r--r--  1 user  staff   606M Nov  7 07:35 build/libs/javacv_url_image_loader-1.0-SNAPSHOT-all.jar

方法2:必要なライブラリのみ依存関係に追加するパターン

頑張って使ってないもの全部除外するのは面倒なので、はじめからOpenCV部分だけ依存関係に追加すればいいんじゃない?と思ってやったのがこれになります。

dependencies {
    implementation group: 'org.bytedeco', name: 'opencv-platform', version: '4.5.3-1.5.6'
}

↓のpom.xmlを見てjavacv-platformの依存関係を調べて、opencv-platformだけあれば大丈夫そうだなと思ってこの方法試してみて、実際動作的には問題ありませんでした。

javacv/platform/pom.xml at release · bytedeco/javacv
Java interface to OpenCV, FFmpeg, and more. Contribute to bytedeco/javacv development by creating an account on GitHub.

結果としてはJARファイルのサイズを464Mまで削減することができました。

$ ls -lh build/libs/javacv_url_image_loader-1.0-SNAPSHOT-all.jar
-rw-r--r--  1 user  staff   464M Nov  7 07:40 build/libs/javacv_url_image_loader-1.0-SNAPSHOT-all.jar

方法3:必要なライブラリのみ依存関係に追加するパターン その2

方法2でOpenCV以外の依存関係は除外することに成功しました。

ただ、方法2で依存関係に追加したopencv-platformはWindows、macOS、Linux、Android、iOSといったあらゆる環境で動作するように、各環境向けのライブラリファイルも含まれています。

今回作ったアプリは

  • 開発環境はMacまたはWindows、本番環境はLinux
  • 開発環境も本番環境も64ビット版OSで動作

といった前提なので、AndroidやiOS、armやx86環境向けの諸々は依存関係に含めなくても良さそうです。

なので必要な環境向けの依存関係のみ記述してやります。

dependencies {
    implementation group: 'org.bytedeco', name: 'opencv', version: '4.5.3-1.5.6'
    implementation group: 'org.bytedeco', name: 'opencv', version: '4.5.3-1.5.6', classifier: 'linux-x86_64'
   implementation group: 'org.bytedeco', name: 'opencv', version: '4.5.3-1.5.6', classifier: 'macosx-x86_64'
    implementation group: 'org.bytedeco', name: 'opencv', version: '4.5.3-1.5.6', classifier: 'windows-x86_64'
    implementation group: 'org.bytedeco', name: 'openblas-platform', version: '0.3.17-1.5.6'
}

これはopencv-platformpom.xmlの依存関係を見て、必要な環境向けの依存関係だけ抜き出してきたものになります。

javacpp-presets/opencv/platform/pom.xml at release · bytedeco/javacpp-presets
The missing Java distribution of native C++ libraries - bytedeco/javacpp-presets

上記pom.xmlではclassifierの部分は変数化されていますが、大本はここに定義してあります。

javacpp-presets/pom.xml at release · bytedeco/javacpp-presets
The missing Java distribution of native C++ libraries - bytedeco/javacpp-presets

この状態でJARを作ると、204Mまでサイズダウンできました。

$ ls -lh build/libs/javacv_url_image_loader-1.0-SNAPSHOT-all.jar
-rw-r--r--  1 user  staff   204M Nov  7 08:52 build/libs/javacv_url_image_loader-1.0-SNAPSHOT-all.jar

これでもともとのファイルサイズの1/4強までサイズを削減することに成功しました。

方法4:必要なライブラリのみ依存関係に追加するパターン 番外編

基本は方法3と同じで真新しいものはないので番外編としています。

更に依存関係を細かく整理して、さらなるサイズ削減を目指してみます。あまり細かくすると新しい環境に対応したい場合の保守コストが上がるので、個人的には方法3くらいまでで妥協できるならしておくのがいいと思います。

さて、方法3で依存関係にopenblas-platformを含めていましたが、実はこれも各環境向けのライブラリファイルが含まれています。openblas-platformの依存に入っているjavacpp-platformも各環境向けのライブラリが存在します。

といったように、依存関係を下れるだけ下って必要最低限のものだけ追加するようにしてみたら、↓のような感じになりました。

dependencies {
    implementation group: 'org.bytedeco', name: 'opencv', version: '4.5.3-1.5.6'
    implementation group: 'org.bytedeco', name: 'opencv', version: '4.5.3-1.5.6', classifier: 'linux-x86_64'
    implementation group: 'org.bytedeco', name: 'opencv', version: '4.5.3-1.5.6', classifier: 'macosx-x86_64'
    implementation group: 'org.bytedeco', name: 'opencv', version: '4.5.3-1.5.6', classifier: 'windows-x86_64'
    implementation group: 'org.bytedeco', name: 'openblas', version: '0.3.17-1.5.6'
    implementation group: 'org.bytedeco', name: 'openblas', version: '0.3.17-1.5.6', classifier: 'linux-x86_64'
    implementation group: 'org.bytedeco', name: 'openblas', version: '0.3.17-1.5.6', classifier: 'macosx-x86_64'
    implementation group: 'org.bytedeco', name: 'openblas', version: '0.3.17-1.5.6', classifier: 'windows-x86_64'
    implementation group: 'org.bytedeco', name: 'javacpp', version: '1.5.6'
    implementation group: 'org.bytedeco', name: 'javacpp', version: '1.5.6', classifier: 'linux-x86_64'
    implementation group: 'org.bytedeco', name: 'javacpp', version: '1.5.6', classifier: 'macosx-x86_64'
    implementation group: 'org.bytedeco', name: 'javacpp', version: '1.5.6', classifier: 'windows-x86_64'
}

これでJARファイルを作成すると136Mまでファイルサイズが減りました。

$ ls -lh build/libs/javacv_url_image_loader-1.0-SNAPSHOT-all.jar
-rw-r--r--  1 user  staff   136M Nov  7 09:22 build/libs/javacv_url_image_loader-1.0-SNAPSHOT-all.jar

最終的に当初のJARのファイルサイズの1/5以下までファイルサイズを削減することができました。これでJARファイルの生成とかデプロイがかなり高速化できました。

蛇足ですが、今回はmacOS、Windows、Linuxの3種類のOSで動作するようにしましたが、これをさらに例えばmacOSだけで動けばいいように依存関係を絞ると40M程度までサイズダウンできます。

参考:

Huge APK file size on Android · Issue #654 · bytedeco/javacv
I use gradle option to use javacv on my android apps. compile group: 'org.bytedeco', name: 'javacv-platform', version: '...

コメント