java - 减少java中的内存使用

标签 java jdbc memory-management memory-leaks tomcat8

我有一个 Web 服务 Java 程序,它从数据库中读取 13,000,000 个日期(例如“08-23-2016 12:54:44”)作为字符串。我的开发环境是Java 8,MySQL 5.7和tomcat 8。我声明了一个字符串数组String[] data来存储它。我使用 Guice 将数据数组的初始值注入(inject)为空。但是,内存占用仍然很大。这是我的代码:

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并抛出'java.lang.OutOfMemoryError:GC开销com.mysql.jdbc.MysqlIO.nextRowFast(MysqlIO.java:2174) 中出现“超出限制”错误

这是错误消息的一部分:

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,但是,我不认为增加内存就能解决问题。

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

最佳答案

  1. 必须关闭诸如ResultSet之类的已用资源才能释放底层系统资源。这可以自动完成declaring the resources in a try-block就像 try (ResultSet resultSet =...).

  2. 您可以尝试fetch only a limited number of rows from database当从 ResultSet 请求它们时,而不是立即请求全部。

  3. 当对象不再被引用时,它们就有资格进行垃圾回收。因此,只要引用了数组对象,它的整个大小就会保留在内存中。如果它不再被引用并且虚拟机内存不足,它将能够处理该数组对象,从而可能避免 OutOfMemoryError。

  4. 异常高的内存使用率可以通过 creating a heap dump 进行分析和 exploring it in the tool jvisualvm of the JDK .

关于java - 减少java中的内存使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38802281/

相关文章:

java - java中模式的字符串比较

java - 在 Java 中将 MySQL 数据库项存储在 ArrayList 中

java - 验证用户输入 JDBC 的最佳方式?

c++ - 有没有比编写存储对有状态分配器对象的引用的包装器分配器更好的方法来做到这一点?

android - 在android上获取免费进程内存

java - 如何逐列而不是逐行填充二维数组

java - 将 PdfFormField 添加到大 PDF 时出现异常

java - OnItemSelectedListener 每次都会强制关闭应用程序

java - 停止 neo4j jdbc 将查询打印到控制台

c - 整数的内存分配