java.lang.OutOfMemoryError:执行数百万次查询时出现Java堆空间错误

时间:2011-09-08 15:51:27

标签: java out-of-memory

在我的应用程序中,我需要对MySQL数据库执行数百万次查询。代码如下:

for (int i=0; i< num_rows ; i++) {
   String query2="select id from mytable where x='"+ y.get(i) "'";              
   Statement stmt2 = Con0.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);     
   ResultSet rs2 = stmt2.executeQuery(query2);    
   ... // process result in rs2
   rs2.close(); 
}

其中num_rows约为200万。在600k循环之后,java报告错误并退出:

  

java.lang.OutOfMemoryError:Java堆空间错误。

我的代码有什么问题?我该如何避免这样的错误?

提前致谢!

5 个答案:

答案 0 :(得分:5)

也要关闭你的陈述。

答案 1 :(得分:4)

声明在这里不是一个好的解决方案。请尝试以下代码:

PreparedStatement pre = Con0.prepareStatement("select id from mytable where x=?");

for (int i=0; i< num_rows ; i++) {
   pre.setString(1, y.get(i));
   ResultSet rs2 = pre.executeQuery();
   ... // process result in rs2
   rs2.close(); 
   pre.clearParameters();
}
pre.close();

答案 2 :(得分:2)

我不知道您接受的答案是否已解决您的问题,因为它不会改变可能导致问题的任何问题。

问题是当ResultSet缓存查询返回的所有行时,可以在迭代set或prefetched时存储。我在PostgreSQL JDBC驱动程序中遇到了类似的问题,它在无事件模式下运行时忽略了游标提取大小。

JDBC驱动程序应使用游标进行此类查询,因此您应检查驱动程序有关 fetchSize 参数的文档。或者,您可以自己执行SQL命令来创建游标并获取下一行X行。

答案 3 :(得分:1)

使用preparedStatement,因为在每个循环中只有X的值发生变化,所以在de loop之外声明应该会有所帮助。您至少在显示的代码中也没有关闭使用的语句,这可能无法帮助垃圾收集器释放已用的内存。

答案 4 :(得分:1)

假设您对所有查询使用单个连接,并假设您的代码比您向我们展示的更复杂,那么确保每个Statement和每个ResultSet在完成后都关闭是至关重要的。这意味着你需要一个像这样的try / finally块:

for (int i=0; i< num_rows ; i++) {
  String query2="select id from mytable where x='"+ y.get(i) "'";              
  Statement stmt2 = Con0.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);     
  ResultSet rs2 = null;   
  try {
    rs2 = stmt2.executeQuery(query2);    
    ... // process result in rs2
  } finally {
    try {
      stmt2.close();
    } catch (SQLException sqle) {
      // complain to logs
    }
    try {
      if (rs2 != null) { rs2.close(); }
    } catch (SQLException sqle) {
    }
  }
}

如果您没有积极地和确定地关闭所有结果集和语句对象,并且如果您足够快地执行请求,则内存不足。