• 作成:
  • 更新:

sbtにプロジェクトを移したらアプリケーションがOutOfMemoryErrorを吐くようになった時の対処法

問題

OutOfMemoryError: Java heap space

でこれまでgradleなどで動いていたアプリケーションが死ぬ.

原因

sbtはデフォルトではsbtと同じJVMでアプリケーションを動かそうとします.sbt自身にはメモリを使いすぎないようにリミッターがかかっているので死にます.

By default, a forked process uses the same Java and Scala versions being used for the build and the working directory and JVM options of the current process. This page discusses how to enable and configure forking for both run and test tasks. Each kind of task may be configured separately by scoping the relevant keys as explained below.

sbt Reference Manual — Forking

とのことです.

解決策

sbt Reference Manual — Forking

にあるようにフォークしてsbtと違うJVMをアプリケーションの実行に使ってもらいます.自分の場合は単に

fork := true

しました.

.sbtoptsにmemory設定する方法もあるようですが,私だけがこのプロジェクトを実行するわけではないので,どのメモリ環境も想定するのは無理なのでそれはやめました.OpenJDK 10からは全部使えるようにするオプションがあるようですが…java - How do I start a JVM with unlimited memory? - Stack Overflow

ログが全部エラーになってしまう問題の解決

forkした状態でsbt runすると標準エラー出力の内容を全てエラーログ扱いにしてしまうようです.

改善する方法を探した所

By default, forked output is sent to the Logger, with standard output logged at the Info level and standard error at the Error level. This can be configured with the outputStrategy setting, which is of type OutputStrategy.

sbt Reference Manual — Forking

と書いてあったので,ここを弄ればログが正常になりそうです.

というわけで調べたら

scala - sbt: suppressing logging prefix in stdout - Stack Overflow

というズバリな回答が載っていました.これを使えば解決です.

consoleで結局エラーになるのを解消

forkはrunには対応していますがconsoleには一切対応していないので,consoleでコードを実行したら結局エラーになってしまいます.

なのでプロジェクトに.jvmoptsファイルを作って,-XX:MaxRAMPercentage=90と書くことでメモリの90%までを使って良いと設定しました.

JVMのヒープサイズとコンテナ時代のチューニング - Folioscope