4

I'm writing a simple Scala & Squeryl application. For test purposes, each time I run 'test' in sbt, an in-memory H2 db is created and populated with test data. After each run I can see that memory usage of java.exe (inside which sbt is running) in the Task Manager increases until after 4 or 5 runs it crashes with OutOfMemoryError. Am I missing something that explicitly releases memory used by H2 or Squeryl? By now, I use only Session.create and then Persistence.create. Here is an excerpt from my code:

object Persistence extends Schema {
  val documents = table[IncomeEntity]
  val positions = table[Position]
  val documentToPositions = oneToManyRelation(documents, positions).via(_.id === _.id_income)
}

class PersistenceTests extends FunSuite with BeforeAndAfterAll {

  override protected def beforeAll() {
    Class.forName("org.h2.Driver")
    SessionFactory.concreteFactory = Some(
      () => Session.create(DriverManager.getConnection("jdbc:h2:mem:test"), new H2Adapter)
    )
  }

  test("DDL") {
    transaction {
      Persistence.create
      assert(Persistence.documents.size == 0)
      assert(Persistence.positions.size == 0)
    }
  } 

  test("Insert") {
    transaction {
      Persistence.create
      (1 to 100) map { _ => IncomeMapper.save(new Income) }
      assert(Persistence.documents.size == 100)
    }
  }
}

The messages I get are simply the following:

[info] PersistenceTests:
sbt appears to be exiting abnormally.
  The log file for this session is at C:\Users\Oleg\AppData\Local\Temp\sbt7320472784033855835.log
java.lang.OutOfMemoryError: PermGen space
Error during sbt execution: java.lang.OutOfMemoryError: PermGen space
Oleg Kunov
  • 179
  • 2
  • 12
  • What database URL do you use? Do you close all connections at the end of the test? – Thomas Mueller Mar 04 '12 at 12:34
  • @Thomas Mueller Updated first post. No, I don't close them, I just couldn't figure out how to do that, that's why I asked if I am missing something :) – Oleg Kunov Mar 04 '12 at 13:14
  • The transaction scope opens/closes connections for you (see http://squeryl.org/sessions-and-tx.html) – Tomer Gabel Mar 04 '12 at 15:34
  • Hm, if it's a PermGen problem, then most likely this is not related to the database at all, but to classloading problems or similar... I don't know what it could be then. – Thomas Mueller Mar 04 '12 at 16:16
  • `fork in Test := true` is the surefire way to avoid these types of issues when repeatedly running tests – EdgeCaseBerg Jul 28 '15 at 14:07

2 Answers2

3

Add the following flags to your SBT start-up script: -XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=256m. That should take care of the problem.

UPDATE: If you're still crashing JVM take a look at SBT-revolver + JRebel: https://github.com/spray/sbt-revolver. It will start your app in a forked JVM so your SBT should never crash.

romusz
  • 1,934
  • 13
  • 11
  • +1 for CMSClassUnloadingEnabled - I was actually under the impression there's no way to unload classes on the JVM! @ovk, would LOVE to know if this solves your problem. – Tomer Gabel Mar 04 '12 at 17:55
  • Thanks! This option made things better a lot, the number of times `test` must run to crash the JVM increased to 15-20, but the final result is unfortunately the same. – Oleg Kunov Mar 05 '12 at 15:50
  • @ovk feel free to plus my answer if it's helpful ;) – romusz Mar 06 '12 at 05:34
  • @romusz I would like to, but without 15 reputation I can't :) – Oleg Kunov Mar 06 '12 at 06:00
  • @ovk If you are using Java 1.7, try with IBM JDK 1.7, No PermGen OutOfMemoryErrors :) – Jestan Nirojan Mar 08 '12 at 08:17
  • @ovk I've added the info about SBT-revolver. Use it if you want to eliminate the crashes after 15-20 runs. – romusz Mar 13 '12 at 20:52
1

Without some more details (such as the schema class you're using, OOME stack trace etc.) it's hard to guess. One possibility is that you're generating a Schema class instance on each test run, which gets cached in what is, in my experience, a very ineffective/inefficient way. Make sure you only have one Schema instance (typically just make it an object), and/or add some more information to your question...

Tomer Gabel
  • 4,104
  • 1
  • 33
  • 37
  • No, my Schema is an usual `object`, updated first post (also added (not informative) system messages I get). – Oleg Kunov Mar 04 '12 at 14:29
  • Ooh, permgen error! That definitely matters. Means there's something (ClassLoader instantiation, class compilation etc.) that screws you over; possibly it's because sbt reloads classes on successive tests, and Squeryl has a very complex class graph (taking up much space on the permgen). You can work around this by adding a -XX:MaxPermSize=256m flag, or else try to figure out where the problem is, e.g. by commenting out Class.forName or only creating the Persistence schema once. You can check the permgen utilization stats with jstat -gcutil . – Tomer Gabel Mar 04 '12 at 15:29