我有一个程序发出一个查询,该查询在30个查询中的每个查询的结果集中返回大约150k数据点。我正在尝试清理处理内存,将JVM推向130MB RAM。有两个线程,一个发出数据库查询并获取结果,另一个执行结果处理。
第一个线程获取结果集并将其深层复制到List>中,该列表放在线程之间的共享队列中。第二个线程取消了它,然后将其设置为null。 (目前用于内存使用测试)。第一个线程围绕DB调用,最后将语句和结果集设置为null。注释掉队列和第二个线程,内存使用量为70MB。但是当我把它重新放入时,内存保持在130MB的使用率。任何想法为什么它不会回到70?
Statement stmt = null;
ResultSet rs = null;
try
{
if (conn.isValid(DB_TIMEOUT))
{
String query = msg.getQuery();
Object request = msg.getRequest();
// errorLog.debug("Query Issued to Trend Database: " + query);
stmt = conn.createStatement();
if (!query.isEmpty())
{
stmt.execute(query);
rs = stmt.getResultSet();
}
TrendApp.resultSetProcQueue.put(new ResultData((jTrendDataRequest) request, resultSetToArrayList(rs)));
} catch (SQLException e)
{
errorLog.error("Failed to issue database command: " + e);
} finally
{
if (stmt != null)
{
try
{
stmt.close();
} catch (SQLException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (rs != null)
{
try
{
rs.close();
} catch (SQLException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
在处理方面:
while (true)
{
ResultData result = null;
try
{
try
{
result = (ResultData) TrendApp.resultSetProcQueue.take();
} catch (InterruptedException e)
{
errorLog.error("Unable to fetch message from Data Adapter processing queue.");
}
} finally
{
if (result != null)
{
result.setData(null);
result = null;
}
}
}
这是结果集到ArrayList的转换
public List<HashMap<String, Object>> resultSetToArrayList(ResultSet rs) throws SQLException
{
ResultSetMetaData md = rs.getMetaData();
int columns = md.getColumnCount();
List<HashMap<String, Object>> list = new ArrayList<HashMap<String, Object>>();
while (rs.next())
{
HashMap<String, Object> row = new HashMap<String, Object>(columns);
for (int i = 1; i <= columns; ++i)
{
row.put(md.getColumnName(i), rs.getObject(i));
}
list.add(row);
}
return list;
}
答案 0 :(得分:0)
VM将尝试保留您的峰值大小。 Java可以在更多内存的情况下表现更好,并且在需要时可以很好地进行清理。
针对您的特定问题(限制总内存使用量),只需将-Xmx
设置为您希望分配的最大值,而不是尝试手动清理变量。 Java将为您完成剩下的工作。尝试允许某种额外分配用于“峰值”使用然后强制退回它真的不是一个好主意。
你需要担心的是记忆力不断增长。探查器可以告诉您对象是否未被释放,但您可以通过调用System.gc()
两次然后打印出已用内存量(总内存 - 可用内存,没有内存)来进行自己的迷你内存检查一个实际的“使用”)。如果在内存密集型进程的每次迭代后检查此数字,它不应该增长 - 它应该在特定值附近悬停。
获得准确内存大小所需的gc调用会缩小内存使用量,因此您不希望在生产中执行此操作。它将搞乱Java的整个内存分配/优化系统。