JDBC / SQLite 的内存泄漏

Cli*_*ote 0 java sqlite memory-leaks scala jdbc

我有一些使用 JDBC 访问 SQLite 数据库的代码。

我注意到,每次进行查询时,内存使用量都会增加 - 即使在连接关闭后,内存使用量也不会下降。

这就是我正在做的:

1) 关闭PreparedStatement

2) 关闭ResultSet

3)关闭连接

这是堆转储分析的屏幕截图:

堆转储屏幕截图

它展示了很多java.lang.ref.Finalizer很多的PreparedStatement物体ResultSet

这是代码(它是用 scala 编写的,但应该很容易与 java 进行比较):

val conn: Connection = DriverManager.getConnection(url)


// Gets strings by a query like SELECT .. WHERE foo = ?
def getStringsByQuery(query: String, param: String, field: String):Seq[String] = {

    val st = conn.prepareStatement(query)
    st.setString(1, param) //value of foo = ?
    st.setFetchSize(Integer.MAX_VALUE)
    st.setMaxRows(Integer.MAX_VALUE)

    //Holder of results
    var results = collection.mutable.Seq.empty[String]

    val rs: ResultSet = st.executeQuery()

    //add results to holder
    while (rs.next())
      results :+= rs.getString(field)

    rs.close() //closing ResultSet
    st.close() //closing PreparedStatement
    results
  }
Run Code Online (Sandbox Code Playgroud)

这是我为测试这一点而编写的测试:

test("detect memory leak") {

    log.info("Starting in 10 sec")
    Thread.sleep(10.seconds.toMillis)

    //Calls a method over and over to see if there's a memory leak or not..
    (1 to 1000).par.foreach(i => {
      val randomWord = getRandomWord() //this produces a random word
      val sql = "SELECT foo FROM myTable where bar = ?"
      val results = getStringsByQuery(sql, randomWord, "bar")
    })

    conn.close() //close the connection
    log.info("Closed conn, closing in 30 sec")

    Thread.sleep(1.minutes.toMillis)
  }
Run Code Online (Sandbox Code Playgroud)

当我运行测试时 - 内存使用量从 24.6 GB 稳步增加到 33 GB 并且永远不会下降(即使 ResultSet +PreparedStatement 正在关闭),甚至在 conn 关闭并且线程休眠 1 分钟时 -内存使用量仍然没有下降。

有谁知道这是怎么回事?我将不胜感激任何帮助。

til*_*ave 5

我们在生产环境中运行 sqlite-jdbc,并且在检查堆转储时注意到类似的行为。

这些对象仅位于堆上,因为它们尚未通过垃圾收集器运行。从https://blog.nelhage.com/post/third-kinds-of-leaks/的意义上来说,这是“2 类内存泄漏”,因为对象已被分配并且生存时间比您预期的要长一些。

这给我们带来的问题是,机器会在 Java 堆上保留内存非常长的时间,从而在请求高峰期间遇到内存压力。我们做了一些不同的事情来确保更频繁地收集这些对象。

这些可能与您的用例不匹配,但您可以根据您遇到的情况考虑一些选项。