Search code examples
scalaspraypermgen

Spray: PermGen out-of-memory errors on deployed instance during runtime


I have a large-ish Spray API written with about 60-70 endpoints, and I run it using the spray-can HTTP server on Java 7. While running a large number of automated end-to-end tests against it, I received a java.lang.OutOfMemoryError: PermGen space error.

I have managed to deal with the problem by forcing classes to be unloaded (using -XX:+CMSClassUnloadingEnabled), increasing the Max PermGen size to 1024m and setting the thread stack size to 2m. But I'm worried I'm masking my problems.

My questions are:

  • I thought the PermGen stored class metadata. I can understand how I might run out of PermGen space when compiling the code. But in this case, I didn't compile the code on the machine, and this error hit me a few minutes into running the application as mentioned above. Why?

  • Am I taking the right approach to deal with PermGen space errors? Are there recommended JVM flags for apps run using Spray-Can?

  • When using the CMSClassUnloadingEnabled, do I also need to use UseConcMarkSweepGC in Java 7? This question (CMSPermGenSweepingEnabled vs CMSClassUnloadingEnabled) appears to indicate it applies to Java 6.


Solution

  • It is possible that something in the framework - or by all means your code - is creating classes dynamically (proxies etc). I would suggest that you analyze a heap dump of the application after running a while, or preferably after crashing OutOfMemoryError. Instructions on how to create the dump can be found in this blog post of mine. The analyzis intructions may only be partially applicable in your case. After you have found what is filling up the PermGen, we can try to determine whether it is a leak that needs to be fixed/prevented, or whether you application is just large.

    And yes, for -XX:+CMSClassUnloadingEnabled to have any effect you also need to enable the Concurrent Mark and Sweep garbage collector with -XX:+UseConcMarkSweepGC. However the default GC (usually Parallell in older JVMs and G1 in newer 1.7+) do class unloading by default, even though there seems to be a bug in the Parallell GC related to this.