Я читаю очень большой файл и извлекаю некоторые небольшие части текста из каждой строки. Однако в конце операции у меня осталось очень мало памяти для работы. Похоже, что сборщик мусора не может освободить память после чтения в файле.
Мой вопрос: есть ли способ освободить эту память? Или это ошибка JVM?
Я создал SSCCE, чтобы продемонстрировать это. Он читает в файле размером 1 мб (Java из-за 16-битного кодирования) и извлекает один символ из каждой строки (~ 4000 строк, поэтому должно быть около 8 кб). В конце теста все еще используется 2 МБ!
Исходное использование памяти:
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 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);
}
}