java - 这是内存泄漏还是我刚刚达到了内存中可以保留的对象的限制?

标签 java memory substring

我有两个大型 CSV 文件,其中包含 Web 应用程序用户验证某些信息所需的数据。我定义了一个 ArrayList< String[] > 并打算将两个文件的内容保留在内存中,这样我就不必在每次用户登录并使用该应用程序时读取它们。

但是,在初始化应用程序并尝试读取第二个文件时,我收到了 java.lang.OutOfMemoryError: Java heap space 错误。 (它很好地完成了第一个文件的读取,但在读取第二个文件时挂起,过了一会儿我得到了这个异常)

读取文件的代码非常简单:

ArrayList<String[]> tokenizedLines = new ArrayList<String[]>();

public void parseTokensFile() throws Exception {
    BufferedReader bRead = null;
    FileReader fRead = null;

    try {
        fRead = new FileReader(this.tokensFile);
        bRead = new BufferedReader(fRead);
        String line;
        while ((line = bRead.readLine()) != null) {
            tokenizedLines.add(StringUtils.split(line, fieldSeparator));
        }
    } catch (Exception e) {
        throw new Exception("Error parsing file.");
    } finally {
        bRead.close();
        fRead.close();
    }
}

我读到Java的split函数在读取大量数据时可能会占用大量内存,因为子字符串函数引用了原始字符串,因此某些字符串的子字符串将占用与原始字符串相同的内存量,即使我们只想要几个字符,所以我做了一个简单的分割函数来尝试避免这种情况:

public String[] split(String inputString, String separator) {
    ArrayList<String> storage = new ArrayList<String>();
    String remainder = new String(inputString);
    int separatorLength = separator.length();
    while (remainder.length() > 0) {
        int nextOccurance = remainder.indexOf(separator);
        if (nextOccurance != -1) {
            storage.add(new String(remainder.substring(0, nextOccurance)));
            remainder = new String(remainder.substring(nextOccurance +  separatorLength));
        } else {
            break;
        }
    }

    storage.add(remainder);
    String[] tokenizedFields = storage.toArray(new String[storage.size()]);
    storage = null;

    return tokenizedFields;

}
但这给了我同样的错误,所以我想知道这是否不是内存泄漏,而只是我不能在内存中拥有包含如此多对象的结构。一个文件长约 600,000 行,每行 5 个字段,另一个文件长约 900,000 行,每行字段数量大致相同。

完整的堆栈跟踪是:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at xxx.xxx.xxx.StringUtils.split(StringUtils.java:16)
    at xxx.xxx.xxx.GFTokensFile.parseTokensFile(GFTokensFile.java:36)

那么,在这篇长篇文章之后(抱歉:P),这是分配给我的 JVM 的内存量的限制还是我错过了一些明显的东西并在某处浪费了资源?

最佳答案

在具有 4GB RAM 的 32 位操作系统上,您的 JVM 不会获得超过 2GB 的空间。这是一个上限。

第二个是您启动 JVM 时指定的最大堆大小。查看 -Xmx 参数。

第三个是生活中的事实,您无法将任何 X 单位放入 Y 大小的容器中,其中 X > Y。您知道文件的大小。尝试单独解析每个并查看它们正在消耗什么样的堆。

我建议您下载Visual VM ,安装所有可用的插件,并让它在运行时监视您的应用程序。您将能够看到整个堆、永久代空间、GC 集​​合、哪些对象占用了最多内存等。

获取数据对于所有问题都是无价的,尤其是像这样的问题。没有它,您只是猜测。

关于java - 这是内存泄漏还是我刚刚达到了内存中可以保留的对象的限制?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10863240/

相关文章:

r - 当你有一个向量时,如何在 R 中使用子字符串函数?

list - Haskell中的子字符串

javascript - 对象数组中的子字符串

java - Spring-Maven应用程序无法执行 "mvn spring-boot:run"

java - 为什么别名在 java 方法中不起作用?

java - HTML 表单提交后 Tomcat 8 重定向

iphone - 我释放了所有的内存,但我的程序需要更多,我该怎么办?

objective-c - 从同一个方法中调用一个方法会造成内存泄漏吗?

java - 如果在没有任何选项的情况下运行 JVM,对内存使用有何影响?

c++ - SQL Server 2008,数值库,c++,LAPACK,内存问题