我有一个过程,该过程从Oracle DB获取一个ResultSet,然后使用返回的数据创建对象,然后将一个对象添加到Map中,最后将一个Map加载到内存中的数据网格中。我的最大resultSet可能有3000万条记录。我注意到,在处理了大约1400万条记录后,应用程序的运行速度大大降低。我有-Xmx = 12G和-Xms = 512M。我的应用程序部署在WebLogic 12.2.0.1版和Java 8_66版上。我还注意到托管服务器发出的此消息:
我试图弄清楚如何优化我的代码或JVM配置。这是代码
MyObj myObj = null;
while (rs.next()) {
myObj = new Balance(rs.getString("Field1"), rs.getString("Field2"), rs.getString("Field3"),
....
rs.getString("Field17"), rs.getString("Field18"), rs.getString("Field19"));
Map<String, Account> myMap = new HashMap<>();
myMap.put(rs.getString("FieldA"), new Account(rs.getString("FieldA"), rs.getDouble("FieldC"),
rs.getString("FieldD"), Boolean.FALSE, Boolean.FALSE));
myObj.setAccounts(myMap);
myKey = myObj.getKey();
existingObject = cacheMap.get(myKey);
if (existingObject != null) {
myObj = myObj.merge(existingObject);
}
cacheMap.put(myKey, myObj);
recCount++;
if (recCount % 250000 == 0) {
logger.info("Processed " + recCount + " records.");
}
}
答案 0 :(得分:0)
您可以使用分页并按块检索数据集,然后您的程序可以在处理下一个数据块等时开始处理当前数据块。通过这种方式检索结果集将花费更少的时间。这是一篇有关mySql https://www.xarg.org/2011/10/optimized-pagination-using-mysql/
中的分页的好文章答案 1 :(得分:0)
选项:1
如果您的某些字段的值将是相同的String
,则在创建Balance
和Account
时,请执行String.intern()
。如果有多余的值,这将在内存占用方面带来极大的好处。
在我们的一个应用程序中,数据为2 lacs,在String.intern()
之后,我们看到了50%的收益。
该代码看起来很难看。但是,使用某些实用程序方法,可以减少麻烦。
代码在这里
String str(ResultSet rs, String fieldName)
{
String s = rs.getString(fieldName);
return s == null ? null : s.intern();
}
void somemethod()
{
...
...
while (rs.next()) {
myObj = new Balance(str(rs, "Field1"), str(rs, "Field2"), str(rs, "Field3"), str(rs, "Field17"), str(rs, "Field18"), str(rs, "Field19"));
Map<String, Account> myMap = new HashMap<>();
myMap.put(str(rs, "FieldA"), new Account(str(rs, "FieldA"), str(rs, "FieldC"), str(rs, "FieldD"), Boolean.FALSE, Boolean.FALSE));
myObj.setAccounts(myMap);
...
...
}
...
}
选项:2
这确实是一个内存保护器选项...!
如果使用Java 8 Update 20或更高版本,则可以通过启用标志XX:+UseStringDeduplication
为整个JVM启用此行为。如果您使用G1
GC
参考编号here。您可以在XX:+UseStringDeduplication
中搜索更多参考
选项:3
您真的可以考虑在该merge()
操作中执行的操作,以查看是否进行了任何功能更改以降低内存需求...