【问题标题】:Memory leaks when recreating Squeryl in-memory database重新创建 Squeryl 内存数据库时出现内存泄漏
【发布时间】:2012-03-22 05:25:44
【问题描述】:

我正在编写一个简单的 Scala 和 Squeryl 应用程序。出于测试目的,每次我在 sbt 中运行“测试”时,都会创建一个内存 H2 数据库并填充测试数据。每次运行后,我可以看到任务管理器中 java.exe(在其中运行 sbt)的内存使用量增加,直到运行 4 或 5 次后,它会因 OutOfMemoryError 而崩溃。我是否遗漏了一些明确释放 H2 或 Squeryl 使用的内存的东西?到目前为止,我只使用Session.create,然后是Persistence.create。这是我的代码的摘录:

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)
    }
  }
}

我收到的信息如下:

[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

【问题讨论】:

  • 您使用什么数据库 URL?您是否在测试结束时关闭所有连接?
  • @Thomas Mueller 更新了第一篇文章。不,我没有关闭它们,我只是不知道该怎么做,这就是为什么我问我是否遗漏了什么:)
  • 事务范围为你打开/关闭连接(见squeryl.org/sessions-and-tx.html
  • 嗯,如果是 PermGen 问题,那么这很可能与数据库根本无关,而是与类加载问题或类似问题有关……我不知道那会是什么。
  • fork in Test := true 是在重复运行测试时避免此类问题的可靠方法

标签: scala h2 squeryl


【解决方案1】:

如果没有更多详细信息(例如您正在使用的架构类、OOME 堆栈跟踪等),就很难猜到。一种可能性是,您在每次测试运行时都会生成一个 Schema 类实例,根据我的经验,它会以一种非常低效/低效的方式进行缓存。确保您只有一个 Schema 实例(通常只是将其设为对象),和/或在您的问题中添加更多信息...

【讨论】:

  • 不,我的架构是普通的object,更新了第一篇文章(还添加了(非信息性)我收到的系统消息)。
  • 哦,永久错误!这绝对很重要。意味着有一些东西(ClassLoader 实例化,类编译等)让你感到困惑;可能是因为 sbt 在连续测试中重新加载类,而 Squeryl 有一个非常复杂的类图(在 permgen 上占用了很多空间)。您可以通过添加 -XX:MaxPermSize=256m 标志来解决此问题,或者尝试找出问题所在,例如通过注释掉 Class.forName 或只创建 Persistence 模式一次。您可以使用 jstat -gcutil . 检查 permgen 利用率统计信息
【解决方案2】:

将以下标志添加到您的 SBT 启动脚本中: -XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=256m。 这应该可以解决问题。

更新: 如果您仍然在崩溃 JVM,请查看 SBT-revolver + JRebel:https://github.com/spray/sbt-revolver。它将在分叉的 JVM 中启动您的应用程序,因此您的 SBT 永远不会崩溃。

【讨论】:

  • +1 for CMSClassUnloadingEnabled - 实际上我的印象是无法在 JVM 上卸载类! @ovk,很想知道这是否能解决您的问题。
  • 谢谢!这个选项让事情变得更好了很多,test 必须运行以使 JVM 崩溃的次数增加到 15-20 次,但不幸的是最终结果是一样的。
  • @ovk 如果有帮助,请随时加上我的回答;)
  • @romusz 我想,但没有 15 声望我不能:)
  • @ovk 如果您使用的是 Java 1.7,请尝试使用 IBM JDK 1.7,没有 PermGen OutOfMemoryErrors :)
猜你喜欢
  • 1970-01-01
  • 2017-02-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-08
  • 2011-09-27
  • 2015-07-01
相关资源
最近更新 更多