mysql使用ResultSet时内存(RAM)使用率增加了吗?
我正在使用MySQL和Java来选择约50000条记录。 奇怪的是,当我使用ResultSet和next()方法来读取数据,我看到,在取我的Java应用程序增加RAM的使用。它以255 MB开始并增加到379 MB! 我使用的代码是在这里:mysql使用ResultSet时内存(RAM)使用率增加了吗?
try { Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost/#mysql50#crawler - used in report?" + "user=root&password=&useUnicode=true&characterEncoding=UTF-8");
Statement st = conn.createStatement();
ResultSet rsDBReader = st.executeQuery("SELECT Id, Content FROM DocsArchive");
while (rsDBReader.next()) {
int docId = rsDBReader.getInt(1);
String content = rsDBReader.getString(2);
. . .
}
rsDBReader.close();
st.close();
conn.close();
} catch (Exception e) {
System.out.println("Exception in reading data: " + e);
}
我相信,内存使用量是ResultSet中,而不是程序的其它部分。 在这个程序中,我不需要更新记录,所以我想在完成工作后删除每条记录。 我的猜测是,已经读过的记录不会被删除,程序也不会释放他们的记忆。所以我用了一些技巧来避免这种情况,比如使用下面的代码:
Statement st = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.CLOSE_CURSORS_AT_COMMIT); st.setFetchSize(500);
rsDBReader.setFetchSize(500);
但是他们没有改变任何东西。 :(
所以我需要一些方法,消除行(发行版)的内存已读取。
另一个有趣的一点是,即使在完成功能和关闭的ResultSet,语句和连接,并且要经过该计划的另一部分,仍然是程序存储器的使用不会降低! 谢谢
回答:
我建议你限制在查询中检索行的数量。50000是很多,为什么不能有一个循环其获取,让我们说,1000行每一次?
你可以做到这一点使用limit
语句,描述here。对于您正在处理的数据量来说,最好务实。你目前的选择今天可能会返回50000行,但如果明天增长到100万呢?你的应用程序会窒息。所以,一步一步做你的处理。
回答:
使用Statement.setFetchSize()向驱动程序提供一个提示,告知驱动程序它应该为包含一定行数的数据流传输ResultSet
。据我所知,MySQL连接-J驱动程序不明白的提示和溪流ResultSet
S(但这是在MySQL中的情况下,时间限制为行)。
默认值为0,将确保连接器-J驱动程序将获取完整ResultSet
没有进行流式传输。这就是为什么你需要提供一个明确的值--MySQL的Integer.MIN_VALUE。
声明:
Statement st = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.CLOSE_CURSORS_AT_COMMIT);
不会导致流的ResultSet
(至少不是在它自己的协议)。它仅仅确保了结果集不为“滚动”(即只能在向前的方向上遍历),而不是“可更新的”,并且当事务提交底层光标将被关闭。
如JDBC implementation notes of MySQL所述,必须调用以上语句(不包括ResultSet.CLOSE_CURSORS_AT_COMMIT
参数)并结合Statement.setFetchSize(Integer.MIN_VALUE)
调用来逐个发生流式传输。有关这种情况的相关警告也被记录在案。
请注意,游标的可保存性未在MySQL文档中提到的示例中指定。如果您需要的值不同于Connection.getHoldability()
提供的值,那么此建议可能不适用。
回答:
你看到的其实是正常现象,不必一定表示内存泄漏。 Java中的对象实例在它们变得无法访问后不会立即收集垃圾,大多数Java虚拟机很不愿意将一次分配的内存返回给操作系统。
如果您使用的是最新的Oracle的Java虚拟机的版本,确实需要更积极的垃圾收集器,您可以通过添加以下参数到java命令尝试G1GC实现:
-XX:+ UnlockExperimentalVMOptions - XX:+ UseG1GC
的G1GC垃圾收集器通常回收对象的速度比默认的垃圾收集和未使用的存储器也由过程释放。
回答:
注意有类似的问题与的Postgres的最新版本。为了实现*你需要禁用自动提交对连接connection.setAutoCommit(false)
,并在您的SQL语句(只包含一个分号即语句)使用单个语句游标处理。它为我工作。
Postgres JDBC documentation
以上是 mysql使用ResultSet时内存(RAM)使用率增加了吗? 的全部内容, 来源链接: utcz.com/qa/263259.html