OutOfMemoryError的原因是什么:以下情况下的Java堆空间?

ran*_*ana 4 java mysql heap memory-leaks jdbc

以下代码示例位于一个运行大约200万次的for循环中.

List<String> parameters = new LinkedList<String>();
stmt2 = null;
rs2= null;

//This is line 472
stmt2 = con.prepareStatement("select NAME from TABLE_NAME where FIELD="+ strId);
rs2 = stmt2.executeQuery();

while (rs2.next()) {
    parameters.add(rs2.getString("NAME"));
}
Run Code Online (Sandbox Code Playgroud)

堆栈跟踪:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at com.mysql.jdbc.PreparedStatement.<init>(PreparedStatement.java:437)
    at com.mysql.jdbc.Connection.clientPrepareStatement(Connection.java:2185)
    at com.mysql.jdbc.Connection.prepareStatement(Connection.java:4782)
    at com.mysql.jdbc.Connection.prepareStatement(Connection.java:4687)
    at consistencyCheck.ConsistencyCheck.parameterCheck(ConsistencyCheck.java:472)
    at consistencyCheck.ConsistencyCheck.performConsistencyCheck(ConsistencyCheck.java:316)
    at consistencyCheck.ConsistencyCheck.main(ConsistencyCheck.java:198)
Run Code Online (Sandbox Code Playgroud)

如果需要更多信息,请告诉我.

谢谢.

谢谢大家的答案.我会接受BalusC的回答,因为他先回答.不幸的是,由于声誉不够,我无法提出任何其他答案:(

对所有建议增加内存堆的人都要注意.增加内存堆是你永远不应该做的事情,除非你100%确定这是你问题的唯一解决方案.例如,在我的问题中,增加堆可能会"解决"问题,但潜在的错误仍然存​​在.

Bal*_*usC 13

基于这些注释,您似乎在循环内部创建Statement并且ResultSet从不关闭它们.你也需要在循环中关闭它们.这将释放内部资源.

此外,您并没有真正从准备好的语句的DB缓存中受益.现在,您在SQL字符串中串联连接参数,这会导致创建2M String对象而不是1 String对象.在循环之前更好地准备语句.

try {
    // ...
    statement = connection.prepareStatement("select NAME from TABLE_NAME where FIELD=?");

    for ( /* 2M times? */ ) {
        statement.setInt(1, id);

        try {
            resultSet = statement.executeQuery();
            // ...
        } finally {
            if (resultSet != null) try { resultSet.close(); } catch (SQLException ignore) {}
        }
    }
} finally {
    if (statement != null) try { statement.close(); } catch (SQLException ignore) {}
}
Run Code Online (Sandbox Code Playgroud)

或者,您也可以考虑使用IN子句.例如

WHERE field IN (1,2,3,4,5);
Run Code Online (Sandbox Code Playgroud)

然而,占位符更加棘手.另请参阅:使用JDBC参数化IN子句的最佳方法是什么?

或作为一个完全不同的替代方案,必要时用更有经验的DB管理员/ SQL忍者的帮助下,重写了整个事情,让你得到正是你需要的只是结果一个 SQL查询.如果有必要,可以在SO 上询问有关的单独问题.


Vis*_*ani 5

完成while循环之后a rs2.close() &stmt2.close() 会有所帮助.