我有两个大型 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 的内存量的限制,还是我遗漏了一些明显的东西并在某处浪费了资源?