我有两个大型 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/