为什么这个简单的scala代码占用了大量内存并最终崩溃? (Play framework 2.0)

时间:2012-03-22 21:12:02

标签: scala playframework-2.0 anorm

我在play framework 2.0中尝试使用一个简单的scala代码来填充我的数据库(存在其他选项,例如直接在数据库中导入SQL文件,但这不是重点):

def filldb = Action {
  import play.api.db.DB
  import anorm._

  var result: Boolean = false

  val tuples: List[(Long, String)] = DB
    .withConnection("playground") { implicit c =>

      for (i <- 1 until 1000000) {
        SQL("""
            INSERT INTO article (
                id,
                title
            ) VALUES (
                """ + i + """,
                'Article no """ + i + """');"""
        ).executeUpdate()

        if (i % 1000 == 0) println("i:" + i)
      }

      val sqlQuery = SQL("select id, title from article order by id;")

      sqlQuery().map(row =>
        row[Long]("id") -> row[String]("title")).toList
    }
  Ok("done")
}

运行良好一段时间(200K迭代),减速,逐渐耗尽内存(最高1.8GB),最后因内存不足而崩溃。

有人可以解释一下导致这种行为的原因吗? 很明显,可以用不同的方式对它进行编码,但关键是要理解错误,以便错误不会在另一个环境中完成......

完成后,详细信息如下:

  • OS:mac 10.6.8
  • play:2.0
  • 数据库:mysql 5.5.12
  • 表:

    CREATE TABLE article (
    id bigint(20) NOT NULL UNIQUE,
    title varchar(255) NOT NULL,
    PRIMARY KEY (id)
    );
    

尝试了这一点,但没有取得更多成功:

def filldb = Action {
  import play.api.db.DB
  import anorm._

  var result: Boolean = false
  val connection = DB.getConnection("playground")

  for (i <- 1 until 1000000) {
        SQL("""
            INSERT INTO article (
                id,
                title
            ) VALUES (
                """ + i + """,
                'Article no """ + i + """');"""
        ).executeUpdate()(connection)

        if (i % 1000 == 0) println("i:" + i)
      }

  val tuples: List[(Long, String)] = {

      val sqlQuery = SQL("select id, title from article order by id;")

      sqlQuery()(connection).map(row =>
        row[Long]("id") -> row[String]("title")).toList
    }

  connection.close()

  Ok("done")
}

不是更好:停留在283k迭代......

2 个答案:

答案 0 :(得分:0)

我的第一个猜测是你可能仍在使用内存数据库中的默认值。你能检查并确保你的conf / application.conf没有使用jdbc:h2:mem:play?如果是这样,你的所有参赛作品都会填满你的记忆。

此外,您创建的每个语句都会打开一个语句对象,该对象在withConnection块结束之前不会关闭。由于你有一百万人坐在记忆中,这可能会积累起来。见http://www.playframework.org/documentation/2.0/ScalaDatabase

您可以尝试在查询操作之外填充数据库。我会尝试做1000批1000,并看看是否能识别你的问题。

答案 1 :(得分:0)

我认为你的问题在于:

val tuples: List[(Long, String)] = {

  val sqlQuery = SQL("select id, title from article order by id;")

  sqlQuery()(connection).map(row =>
    row[Long]("id") -> row[String]("title")).toList
}

您正在填充包含数据库中所有行的映射,因此您要使用1M行填充Scala / Java数据结构。

你真的一次需要一百万行吗?或者你是否需要以分页方式(即前20个,第二个20等等)。

这不是游戏问题,即使使用java和单个普通jdbc测试,您也会遇到同样的问题。告诉我们元组的真实用法,我们可以提供一些建议。