大量对象的优化

时间:2018-08-17 17:46:44

标签: java performance optimization

我有一个过程,该过程从Oracle DB获取一个ResultSet,然后使用返回的数据创建对象,然后将一个对象添加到Map中,最后将一个Map加载到内存中的数据网格中。我的最大resultSet可能有3000万条记录。我注意到,在处理了大约1400万条记录后,应用程序的运行速度大大降低。我有-Xmx = 12G和-Xms = 512M。我的应用程序部署在WebLogic 12.2.0.1版和Java 8_66版上。我还注意到托管服务器发出的此消息:

  1. JVM暂停时间可能太长:

我试图弄清楚如何优化我的代码或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.");
        }
    }

2 个答案:

答案 0 :(得分:0)

您可以使用分页并按块检索数据集,然后您的程序可以在处理下一个数据块等时开始处理当前数据块。通过这种方式检索结果集将花费更少的时间。这是一篇有关mySql https://www.xarg.org/2011/10/optimized-pagination-using-mysql/

中的分页的好文章

答案 1 :(得分:0)

选项:1

如果您的某些字段的值将是相同的String,则在创建BalanceAccount时,请执行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()操作中执行的操作,以查看是否进行了任何功能更改以降低内存需求...