Web アプリケーションのユーザーが情報を検証するために必要なデータを含む 2 つの大きな CSV ファイルがあります。ArrayList< String[] > を定義し、ユーザーがログインしてアプリケーションを使用するたびにそれらを読み取る必要がないように、両方のファイルの内容をメモリに保持するつもりでした。
ただし、アプリケーションを初期化して 2 番目のファイルを読み取ろうとすると、java.lang.OutOfMemoryError: Java heap space が発生します。(最初のファイルの読み取りは正常に終了しますが、2番目のファイルの読み取り時にハングし、しばらくするとその例外が発生します)
ファイルを読み取るためのコードは非常に単純です。
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 の分割関数は大量のデータを読み取るときに大量のメモリを使用する可能性があることを読みました。数文字だけが必要なので、これを回避するために単純な分割関数を作成しました。
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;
}
ただし、これにより同じエラーが発生するため、メモリリークではなく、メモリ内に非常に多くのオブジェクトを持つ構造を持つことができないのではないかと考えています。1 つのファイルの長さは約 600,000 行で、1 行あたり 5 つのフィールドがあり、もう 1 つのファイルは約 900,000 行の長さで、1 行あたりのフィールド数はほぼ同じです。
完全なスタック トレースは次のとおりです。
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 に割り当てられたメモリ量の制限ですか、それとも明らかな何かが欠けていて、どこかでリソースを無駄にしていますか?