私は非常に大きなファイルを読んでいて、各行からテキストのいくつかの小さな部分を抽出しています。しかし、操作の終わりに、私は作業するためのメモリがほとんど残っていません。ガベージコレクターは、ファイルを読み込んだ後、メモリを解放できないようです。
私の質問は:このメモリを解放する方法はありますか?それとも、これはJVMのバグですか?
これを実証するためにSSCCEを作成しました。1 mb(16ビットエンコーディングのためJavaでは2 mb)ファイルを読み込み、各行から1文字を抽出します(約4000行なので、約8 kbにする必要があります)。テストの終了時に、2 mb全体がまだ使用されています!
初期メモリ使用量:
Allocated: 93847.55 kb
Free: 93357.23 kb
ファイルを読み込んだ直後(手動のガベージコレクションの前):
Allocated: 93847.55 kb
Free: 77613.45 kb (~16mb used)
プログラムはファイルの読み取りに多くのリソースを使用しているため、これは予想されることです。
ただし、ガベージコレクションを実行しますが、すべてのメモリが解放されるわけではありません。
Allocated: 93847.55 kb
Free: 91214.78 kb (~2 mb used! That's the entire file!)
ガベージコレクターを手動で呼び出しても、保証が得られないことはわかっています(場合によっては怠惰です)。ただし、これは、ファイルが使用可能なメモリのほとんどすべてを消費し、プログラムの残りの部分が必要であるにもかかわらずメモリを使い果たしてしまう、私の大きなアプリケーションで発生していました。この例は、ファイルから読み取られた余分なデータが解放されていないという私の疑いを裏付けています。
テストを生成するためのSSCCEは次のとおりです。
import java.io.*;
import java.util.*;
public class Test {
public static void main(String[] args) throws Throwable {
Runtime rt = Runtime.getRuntime();
double alloc = rt.totalMemory()/1000.0;
double free = rt.freeMemory()/1000.0;
System.out.printf("Allocated: %.2f kb\nFree: %.2f kb\n\n",alloc,free);
Scanner in = new Scanner(new File("my_file.txt"));
ArrayList<String> al = new ArrayList<String>();
while(in.hasNextLine()) {
String s = in.nextLine();
al.add(s.substring(0,1)); // extracts first 1 character
}
alloc = rt.totalMemory()/1000.0;
free = rt.freeMemory()/1000.0;
System.out.printf("Allocated: %.2f kb\nFree: %.2f kb\n\n",alloc,free);
in.close();
System.gc();
alloc = rt.totalMemory()/1000.0;
free = rt.freeMemory()/1000.0;
System.out.printf("Allocated: %.2f kb\nFree: %.2f kb\n\n",alloc,free);
}
}