subString()などのメソッドで新しいStringインスタンスの新しいchar配列が作成されないように、JavaStringがその中のchar配列を再利用することに気づきました。この目的のために、Stringにはいくつかの非公開コンストラクターがあり、文字列配列と2つのintを範囲として受け入れてStringインスタンスを構築します。
しかし、今日まで、splitは元のStringインスタンスのchararrも再利用することがわかりました。ここで、ファイルからloooooong行を読み取り、それを「、」で分割し、実際の使用のために非常に制限された列を切り取りました。行のすべての部分がlooooongchar配列の参照を密かに保持しているため、すぐにOOOを取得しました。
ここにサンプルコードがあります:
ArrayList<String> test = new ArrayList<String>(3000000);
BufferedReader origReader = new BufferedReader(new FileReader(new File(
"G:\\filewithlongline.txt")));
String line = origReader.readLine();
int i = 0;
while ((line = origReader.readLine()) != null) {
String name = line.split(',')[0];
test.add(name);
i++;
if (i % 100000 == 0) {
System.out.println(name);
}
}
System.out.println(test.size());
吐き出されたすべてのStringインスタンスが「浅いコピー」ではなく「実際の深いコピー」であることを確認するためのJDKの標準的な方法はありますか?
現在、非常に醜い回避策を使用して、新しいStringインスタンスを強制的に作成しています。
ArrayList<String> test = new ArrayList<String>(3000000);
BufferedReader origReader = new BufferedReader(new FileReader(new File(
"G:\\filewithlongline.txt")));
String line = origReader.readLine();
int i = 0;
while ((line = origReader.readLine()) != null) {
String name = line.split(',')[0]+" ".trim(); // force creating a String instance
test.add(name);
i++;
if (i % 100000 == 0) {
System.out.println(name);
}
}
System.out.println(test.size());