Чтение большого файла в массив java.lang.OutOfMemoryError: пространство кучи Java

Я пытаюсь прочитать очень большой файл в массив. очевидно, что я не читаю его в массив в данный момент, но это не проблема, с которой я сталкиваюсь. это около 600 миллионов цифр, и это, кажется, вызывает ошибку. Исключение в потоке «основной» java.lang.OutOfMemoryError: пространство кучи Java

BufferedReader brWorld = null;
String World;
brWorld = new BufferedReader(new FileReader("Saves/" + Name));
World = brWorld.readLine();
String Numbers = World;
String[] LoadWorld = Numbers.split("");
for(int x = 0; x < MaterialArray.length * MaterialArray.length; x++){
    System.out.println(String.valueOf(LoadWorld[x]));
}

Я загружаю бы в массив для моей игры. Есть ли способ загрузить такой большой текстовый файл? спасибо Лиам


person user3543533    schedule 17.04.2014    source источник
comment
Только увеличение RAM, если вам действительно нужен весь файл в памяти. В противном случае читайте по частям   -  person kosa    schedule 17.04.2014
comment
Пожалуйста, НЕ называйте переменные первой буквой в верхнем регистре, существует строгое соглашение Java, чтобы начинать переменные со строчных букв, и это делает ваш код нечитаемым для разработчиков Java.   -  person amit    schedule 17.04.2014
comment
String[] LoadWorld = Numbers.split(); Вы действительно имели в виду пустую строку? чего вы пытаетесь достичь?   -  person amit    schedule 17.04.2014
comment
я знаю, что код работает. он просто перестает работать, когда файл слишком большой   -  person user3543533    schedule 17.04.2014
comment
@ user3543533 посмотри мое решение твоей проблемы. Вы должны использовать string.charAt() вместо того, чтобы разбивать строку на массив.   -  person John    schedule 17.04.2014


Ответы (2)


Во-первых, вам понадобится много памяти для этого. Несколько ГБ оперативной памяти, не считая комнаты GC.

Если вы читаете «одну строку» из 600 миллионов цифр, в конце концов, после того, как строка будет фактически прочитана (вы, вероятно, даже не доберетесь до этого места), строка из 600 миллионов цифр потребует 1,2 ГБ памяти, просто для персонажи.

Java хранит строки как массивы символов, а символы хранятся внутри как UTF-16, что составляет 2 байта.

Это само по себе отправляет требования к памяти через крышу.

Когда вы выполняете разделение, вы превращаете каждую цифру в отдельную строку. Теперь у вас есть 600 миллионов строк и все связанные с этим накладные расходы. Как минимум, вы просматриваете не менее 16 байтов на строку, поскольку в ней хранится указатель на базовый массив, смещение в массиве и длина строки. К счастью, split на самом деле повторно использует базовый массив, но здесь это не очень помогает.

16 байт * 600M — это 9,6 ГБ.

Теперь мы определенно переходим к «смехотворной» сфере требований к памяти.

Вы не говорите, что вы на самом деле хотите сделать. Вы хотите "загрузить файл", но не говорите в какой. Таким образом, трудно дать рекомендацию о том, как это должно быть сделано. Если вы хотите просто распечатать файл, вы можете просто прочитать каждый символ один за другим и распечатать его, но это явно не цель.

Так что пока, да, можно "кинуть память" на эту проблему, не хочется. Вам нужно изучить проблему и придумать лучшее представление о том, чего вы пытаетесь достичь, и работать исходя из этого.

person Will Hartung    schedule 17.04.2014

Вот почему у вас заканчивается память:

brWorld = new BufferedReader(new FileReader("Saves/" + Name));
World = brWorld.readLine();
String Numbers = World;
String[] LoadWorld = Numbers.split("");

Вы сначала читаете все цифры:

600,000,000 chars = 600,000,000 bytes = 600 MB

Итак, у вас уже минимум 600 МБ. Затем вы создаете совершенно новый массив строк. Это означает, что вы создаете указатель String для каждого символа в массиве. В зависимости от вашей архитектуры это может быть 4 байта или больше:

600 MB + 600,000,000 * 4 = 600 MB + 2,400 MB = 3,000 MB = 3 GB

*Эти цифры приблизительны, и я знаю, что фактическая сумма, вероятно, НАМНОГО больше.

Как видите, это вообще не осуществимое решение. Это НАМНОГО лучшее решение:

BufferedReader brWorld = null;
String world;
brWorld = new BufferedReader(new FileReader("Saves/" + Name));
world = brWorld.readLine();
for(int x = 0; x < MaterialArray.length * MaterialArray.length; x++){
    System.out.println(String.valueOf(world.charAt(x)));
}
person John    schedule 17.04.2014
comment
Это намного больше 600 МБ. Он создает 600 000 000 String объектов, каждый из которых весит намного больше 1 миллиарда... - person amit; 17.04.2014