Java JDBC/SQLite内存泄漏
我有一些使用JDBC访问SQLite数据库的代码 我注意到,每次进行查询时,内存使用量都会增加,即使在连接关闭后,内存使用量也不会下降 以下是我正在做的: 1) 关闭Java JDBC/SQLite内存泄漏,java,scala,sqlite,jdbc,memory-leaks,Java,Scala,Sqlite,Jdbc,Memory Leaks,我有一些使用JDBC访问SQLite数据库的代码 我注意到,每次进行查询时,内存使用量都会增加,即使在连接关闭后,内存使用量也不会下降 以下是我正在做的: 1) 关闭PreparedStatement 2) 关闭结果集 3) 关闭连接 以下是heapdump分析的屏幕截图: 它显示了许多java.lang.ref.Finalizer和许多PreparedStatement和ResultSet对象 下面是代码(在scala中,但应该很容易与java进行比较): 以下是我编写的测试,用于测试: t
PreparedStatement
2) 关闭结果集
3) 关闭连接
以下是heapdump分析的屏幕截图:
它显示了许多java.lang.ref.Finalizer
和许多PreparedStatement
和ResultSet
对象
下面是代码(在scala中,但应该很容易与java进行比较):
以下是我编写的测试,用于测试:
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)
}
当我运行测试时—内存使用量从24.6 GB稳步增加到33 GB,并且从未下降(即使ResultSet+PreparedStatement正在关闭),甚至在连接关闭且线程休眠1分钟时—内存使用量仍然没有下降
有人知道这里发生了什么吗?非常感谢您的帮助。我们在生产环境中运行sqlite jdbc,并且在检查堆转储时注意到类似的行为 这些对象仅在堆上,因为它们尚未通过垃圾收集器运行。从某种意义上说,这是一种“类型2内存泄漏”,因为对象已经分配,并且比您预期的要长一点 这给我们带来的问题是,机器将在Java堆上保留内存,时间出乎意料地长,在请求高峰时会遇到内存压力。我们做了一些不同的事情来确保更频繁地收集这些对象
- 减少总体Java堆大小。这可以确保垃圾收集器看到清理这些对象的更多需要。我们的工作负载在SQLite上非常紧张,因此机器内存最好通过JNI进入堆外内存,而不是在Java堆上分配
- 调整G1GC垃圾收集器,以便为newgen分配更多堆,因为这些对象通常寿命很短。()
- 增加垃圾收集器日志记录,并通过GCEasy()之类的服务运行它们,以准确了解正在进行的垃圾收集器运行类型,以便进行进一步的调优
<>这些可能与你的用例不匹配,但是这些是你可以根据你所遇到的问题考虑的一些选项。 < P>我通过将我的SQLite数据集移植到CQEngine来解决这个问题。非常高兴。我关闭了连接和数据库对象,创建了一个具有相同参数和新连接的新对象数据库,最后称为垃圾收集 根据需要重复此过程。我做了一个计数器,当我填满电脑的一半内存时,重复这个过程
现在我可以正常运行了。关闭连接每次迭代无差异@user7294900I还更新到了最新版本的SQLite驱动程序-无差异ID您尝试添加try子句了吗?@user7294900我相信在这种情况下不必这样做,因为资源正在直接关闭,没有任何异常发生嘿tildedave—您是否也使用JDBC访问SQLite?您是否也看到未进行GC的PreparedStatements/ResultSet?它们最终是GC的吗?如果是,大约需要多长时间?是的,我们使用xerial sqlite库运行sqlite jdbc,基本上就像你的问题一样。这些服务一次运行几天或几周。(将答案编辑得更清楚一点。)我不确定收集对象的时间尺度。它确实取决于您如何配置垃圾收集器,因此,如果您发现问题(超出测试用例),您可以开始查找。您是否能够共享您最终使用的GC设置?因此,我们的GC设置非常特定于我们的应用程序,我不确定它们是否普遍有用。我们得到的主要好处是减少了堆的大小,如果您在应用程序中发现内存问题,我将从这一点开始。我们目前还覆盖了InitiatingHeapOccupencyPercent(更频繁地使用GC)、G1OldCsetRegionResholdPercent(更频繁地使用GC)、G1MaxNewSizePercent(为新对象提供更多堆空间),这也很有帮助。
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)
}