現象
Specs2 でゴリゴリテストを書いていると、Spec クラスが多くなって、私の環境では下記のような OutOfMemoryError が発生してしまいました。
Internal error when running tests: java.lang.OutOfMemoryError: PermGen space
Exception in thread "Thread-7" java.io.EOFException
at java.io.ObjectInputStream$BlockDataInputStream.peekByte(ObjectInputStream.java:2598)
...(snip)...
前提
私の環境は下記の通りなので、下記環境を前提にします。
環境 | バージョン |
---|---|
Mac OSX | 10.9.5 |
Scala | 2.11.2 |
sbt(activator) | 0.13.5 |
Specs2 | 2.13.2 |
ハマった点
まず初めに PermGen Space が足りてないということなのでプロセスを確認してみます。
$ ps auxww | grep java
2:uryu 14470 232.2 9.5 4089996 797916 s002 R+ 10:44AM 1:27.16 /Library/Java/JavaVirtualMachines/jdk1.7.0_65.jdk/Contents/Home/bin/java -Dactivator.home=/Users/uryu
/workspace/push/push-notification -Xms1024m -Xmx1024m -XX:PermSize=64m -XX:MaxPermSize=256m -Xmx1024m -XX:ReservedCodeCacheSize=128m -Dsbt.log.format=true -Dconfig.file=module/api/c
onf/uryu-local.conf -Dlogger.file=module/api/conf/uryu-local-logger.xml -jar /Users/uryu/workspace/push/push-notification/activator-launch-1.2.10.jar
「--XX:MaxPermiSize=256m」となっているのにもかかわらず、
OutOfMemoryErrorになるのかよ…
activator の起動スクリプトを直接書き換えて「--XX:MaxPermiSize=512m」「--XX:MaxPermiSize=1024m」として再度テストを実行しても OutOfMemoryError が発生してしまいました。。
解決策
テスト実行中にプロセスを確認してみると
$ ps auxww | grep java
2:uryu 14595 100.2 14.3 3989124 1196096 s002 R+ 10:45AM 3:38.82 /Library/Java/JavaVirtualMachines/jdk1.7.0_65.jdk/Contents/Home/jre/bin/java -Xmx1024m -classpath /Users/uryu/workspace/push/push-notification/module/api/target/scala-2.11/test-classes
...(snip)...
15:uryu 14470 0.1 11.7 4094620 985032 s002 S+ 10:44AM 2:14.19 /Library/Java/JavaVirtualMachines/jdk1.7.0_65.jdk/Contents/Home/bin/java -Dactivator.home=/Users/ury
u/workspace/push/push-notification -Xms1024m -Xmx1024m -XX:PermSize=64m -XX:MaxPermSize=256m -Xmx1024m -XX:ReservedCodeCacheSize=128m -Dsbt.log.format=true -Dconfig.file=module/api/
conf/uryu-local.conf -Dlogger.file=module/api/conf/uryu-local-logger.xml -jar /Users/uryu/workspace/push/push-notification/activator-launch-1.2.10.jar
2つプロセスがあります。
テスト用のプロセスは親の activator から Fork された別プロセスだったんですね。(誰かに聞いた気がするけど失念してた)
これじゃあ、いくら activator のプロセスの Perm Size 変更してもテスト実行時は OutOfMemoryError になります。
テストもしくはアプリケーションのjavaOptionを変更/追加したい場合は build.sbt に下記のように記載すると良いようです。
build.sbt
// activator の javaOptions を引き継ぎたい場合
javaOptions ++= sys.process.javaVmArguments.filter(a => Seq("-Xmx", "-Xms", "-XX").exists(a.startsWith))
or
// 自分で決めちゃう(テスト時のみ)
javaOptions in Test += "--XX:MaxPermSize=256m"