【发布时间】:2019-08-28 14:56:40
【问题描述】:
我需要在 postgres DB 上使用 java 运行一些查询。问题是当我使用此代码执行查询时,我的内存增加了,即使我关闭了语句并且结果集内存仍在增加。当然,GC 会被执行,但问题是有时 GC 是在查询执行过程中执行的,它会改变我查询的执行时间。我如何解决这个问题以防止在 SQL 查询中间执行 GC 并在我的情况下防止内存泄漏?
public long getStatementExecutionTimeInMilliseconds( final String sqlQuery,
final int fetchSize, final boolean fetchAttributesFlag,
Integer numberOfSelectedFields) throws SQLException {
Statement stmt = null;
ResultSet rs = null;
int numberOfResult = 0;
if (numberOfSelectedFields == null) {
numberOfSelectedFields = getNumberOfSelectedFields(sqlQuery);
}
long start = 0;
try {
stmt = createStatement (fetchSize);
stmt.executeQuery (sqlQuery);
start = System.currentTimeMillis ();
rs = stmt.executeQuery (sqlQuery);
while (rs.next ()) {
if (fetchAttributesFlag) {
for (int i = 1; i <= numberOfSelectedFields; i++) {
rs.getInt (i);
}
}
}
stmt.close ();
}
finally {
DatabaseUtils.tryClose(rs);
DatabaseUtils.tryClose(stmt);
}
//System.out.println (numberOfResult);
final long executionTimeInMilliseconds = System.currentTimeMillis() - start;
return executionTimeInMilliseconds;
}
【问题讨论】:
-
为什么要执行两次语句?为什么您认为内存配置文件表示内存泄漏而不仅仅是正常的系统使用情况?
-
我关闭语句只是为了确保语句将被释放,即使我关闭语句并且结果集内存仍然增加,并且仅在我执行查询时才会发生。为什么执行(查询)会消耗大量内存而没有释放它。
-
清除旧对象是垃圾收集器的工作,它会在确定需要运行时执行。在它运行之前,对象将停留在等待收集的堆上。这并不意味着存在内存泄漏。
-
好的。但是例如我需要执行相同的查询3次,问题是在某些情况下GC会在执行过程中执行,这会影响执行时间。
-
减少 SQL 执行的内存占用虽然有用,但不会阻止 GC 进行完整收集,只会降低它们的常见性,从而降低在执行期间发生这种情况的可能性一个问题。您可能应该查看 CMS 和 G1 垃圾收集器,看看它们是否更适合您。还值得研究对从数据库中拉回的结果进行分页。更大的页面意味着内存中保存的结果更多,但返回数据库以获取下一页数据的往返次数更少。
标签: java postgresql jdbc memory-management garbage-collection