Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/394.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用ResultSet时mysql内存(RAM)使用量增加?_Java_Mysql_Memory Management_Resultset - Fatal编程技术网

Java 使用ResultSet时mysql内存(RAM)使用量增加?

Java 使用ResultSet时mysql内存(RAM)使用量增加?,java,mysql,memory-management,resultset,Java,Mysql,Memory Management,Resultset,我正在使用MySQL和Java选择大约50000条记录。 奇怪的是,当我使用ResultSet和next()方法读取数据时,我发现java应用程序的RAM使用在抓取过程中增加了。它从255MB开始,增加到379MB! 我使用的代码如下: try { Class.forName("com.mysql.jdbc.Driver"); Connection conn = DriverManager.getConnection("jdbc:mysql://localhost/#mysql5

我正在使用MySQL和Java选择大约50000条记录。 奇怪的是,当我使用ResultSet和next()方法读取数据时,我发现java应用程序的RAM使用在抓取过程中增加了。它从255MB开始,增加到379MB! 我使用的代码如下:

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
语句来实现这一点。对于您正在处理的数据量,最好始终保持务实。您当前的select今天可能返回50000行,但如果明天它增长到一百万行会怎么样?您的应用程序将阻塞。因此,请逐步进行处理。

用于向e驱动程序,它应该为包含一定行数的数据流传输
ResultSet
。据我所知,MySQL Connector-J驱动程序确实理解提示并流传输
ResultSet
s(但在MySQL的情况下,一次只能流一行)

默认值为0,将确保Connector-J驱动程序将获取完整的
ResultSet
,而不进行流式处理。这就是为什么在MySQL中需要提供一个显式值-Integer.MIN_值

声明:

Statement st = conn.createStatement( ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.CLOSE_CURSORS_AT_COMMIT);
不会导致流式传输
结果集
(至少不是自动进行的)。它仅确保结果集不可“滚动”(即只能向前移动)且不可“更新”,并且在事务提交时,基础游标将关闭

如中所述,上述语句(不带
ResultSet.CLOSE\u CURSORS\u AT\u COMMIT
参数)必须与
语句.setFetchSize(Integer.MIN\u VALUE)
调用一起调用,才能逐行进行流式处理。此类场景中涉及的相关注意事项也已记录在案


请注意,MySQL文档中提到的示例中没有指定游标的可保持性,同样,此建议可能不适用。

您看到的实际上是预期行为,不一定表示内存泄漏。对象实例在无法访问后不会立即在Java中进行垃圾收集,大多数Java虚拟机在分配内存后都不愿意返回操作系统。

如果您使用的是Oracle Java VM的最新版本,并且确实需要更具攻击性的垃圾收集器,则可以通过向Java命令添加以下参数来尝试G1GC实现:

-XX:+UnlockExperimentalVMOptions-XX:+UseG1GC


G1GC垃圾回收器回收对象的速度通常比默认垃圾回收器快,未使用的内存也会被进程释放。

请注意,最新版本的Postgres也存在类似问题。为了实现游标处理,需要禁用连接时的自动提交
connection.setAutoCommit(false)
并在SQL语句中使用一条语句(即只包含一个分号的语句)。这对我很有用


MySQL缓存查询结果。好的,谢谢,但是我如何清空cach?您可以做些什么来节省内存(不过需要更多时间)是限制每个SELECT语句获得的结果数否,MySQL JDBC驱动程序对控制获取大小的支持非常有限。默认行为是一次获取SELECT的整个结果。若要流式传输结果,必须将获取大小设置为Integer.MIN_值,并使用ResultSet.TYPE_创建语句仅WARD_,ResultSet.CONCUR_只读。这样做,必须考虑文档中指出的其他一些限制:我使用了以下代码:st.setFetchSize(500);rsDBReader.setFetchSize(500);但这一点没有改变thing@Soheil,文档很清楚500不会触发提示。我建议先阅读它们。如果你想快速回答,使用
Integer.MIN\u值
而不是500可能有效。@Vinet Reynolds,你是对的。我用Integer.MIN\u值测试了它。它有效。