首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >减少java中的内存使用量

减少java中的内存使用量
EN

Stack Overflow用户
提问于 2016-08-06 16:38:05
回答 2查看 1.6K关注 0票数 0

我有一个web服务Java程序,它从数据库中读取13,000,000日期,如'08-23-2016 12:54:44‘作为字符串。我的开发环境是Java8,Tomcat5.7和Tomcat8。我声明了一个字符串数组String[]数据来存储它。我使用Guice将数据数组的初始值注入到empty。然而,内存使用量仍然很大。这是我的代码:

代码语言:javascript
复制
String[] data;//size is 1,000,000
void generateDataWrapper(String params) {
        //read over 13000000 dates string
        ResultSet rs = mySQLCon.readData(params);  
        clearData(data);//set to empty string 
        int index = 0;
        while(rs.next()) {
             data[index++] = rs.getString("date");
             if (index == (size - 1)) {//calculate every 1,000,000 total 13 times 
                 //calculate statistics
                 ... 
                 //reset all to empty string
                 clearData(data);    
                 index = 0;
             } 
        }
}
//mySQLCon. readData function
ResultSet readData(String params) {
        try {
             String query = generateQuery(params);
             Statement postStmt = connection.createStatement();
             ResultSet rs = postStmt.executeQuery(query);
        return rs;
        } catch (Exception e) {
        }
        return null;
}

如果我调用此函数一次,内存将达到12G,如果我再次调用它,内存将达到20G,第三次调用时,内存将达到25G,并在com.mysql.jdbc.MysqlIO.nextRowFast(MysqlIO.java:2174)中抛出'java.lang.OutOfMemoryError: GC开销限制超出‘错误

这是错误消息的一部分:

代码语言:javascript
复制
java.lang.OutOfMemoryError: GC overhead limit exceeded
    com.mysql.jdbc.MysqlIO.nextRowFast(MysqlIO.java:2174)
    com.mysql.jdbc.MysqlIO.nextRow(MysqlIO.java:1964)
    com.mysql.jdbc.MysqlIO.readSingleRowSet(MysqlIO.java:3316)
    com.mysql.jdbc.MysqlIO.getResultSet(MysqlIO.java:463)
    com.mysql.jdbc.MysqlIO.readResultsForQueryOrUpdate(MysqlIO.java:3040)
    com.mysql.jdbc.MysqlIO.readAllResults(MysqlIO.java:2288)
    com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2681)
    com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2547)
    com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2505)
    com.mysql.jdbc.StatementImpl.executeQuery(StatementImpl.java:1370)
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    java.lang.reflect.Method.invoke(Unknown Source)

我已经将垃圾收集算法更改为:-XX:+UseConcMarkSweepGC -XX:+CMSIncrementalMode,但这没有帮助。我试过把数据改成静态变量,还是会有这个问题。目前JVM堆是8g,tomcat内存是24g,但是,我认为增加内存并不能解决问题。

我不明白为什么每次我调用这个函数的时候我的内存还在增加,有人能给我一些建议吗?

EN

回答 2

Stack Overflow用户

发布于 2016-08-06 17:52:24

此外,您可以将字符串数组更改为长数组,因为字符串会消耗大量内存。在您的例子中,日期字符串的大小是38字节( 19个字符*2字节),而long只占用8字节的内存。

代码语言:javascript
复制
long[] data;//size is 1,000,000
void generateDataWrapper(String params) {
    //read over 13000000 dates string
    ResultSet rs = mySQLCon.readData(params);
    clearData(data);//set to empty string
    int index = 0;
    SimpleDateFormat formater =  new SimpleDateFormat("MM-dd-YYYY HH:mm:ss");
    while(rs.next()) {
        try{
            Date date = formater.parse(rs.getString("date"));
            data[index++] = date.getTime();
        }catch(ParseException pe) {
            pe.printStackTrace();
        }
        if (index == (size - 1)) {//calculate every 1,000,000 total 13 times
            //calculate statistics
            ...
            //reset all to empty string
            clearData(data);
            index = 0;
        }
    }
}

在任何需要字符串的地方,都可以用下面的代码将其解析回来

代码语言:javascript
复制
SimpleDateFormat formater =  new SimpleDateFormat("MM-dd-YYYY HH:mm:ss");
Date date = new Date(data[i]);
String dateString = formater.format(date);
票数 1
EN

Stack Overflow用户

发布于 2016-08-07 12:05:43

首先,感谢您的所有建议。我已经通过阅读mm759解决了这个问题,并意识到我在完成阅读后忘记关闭ResultSet。在我添加rs.close()之后,每次都需要相同的时间来完成,尽管内存将达到我设置的最大内存。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38802281

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档