Четене на голям файл в масив java.lang.OutOfMemoryError: Java heap space

Опитвам се да прочета изключително голям файл в масив. очевидно е, че в момента не го чета в масив, но това не е проблемът, който имам. той е около 600 милиона цифри и това изглежда го кара да получава грешка. Изключение в нишката "main" java.lang.OutOfMemoryError: Java heap space

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)


Първо, ще ви трябва много памет за това. Няколко GB RAM, без GC стая.

Ако четете „единичен ред“ от 600 милиона цифри, в крайна сметка, след като редът е действително прочетен (вероятно дори няма да стигнете дотук), низът от 600 милиона цифри ще изисква 1,2 GB памет, просто за героите.

Java съхранява низовете като масиви от символи, а символите се съхраняват вътрешно като UTF-16, което е 2 байта.

Само това изпраща изискванията за памет през покрива.

Когато правите своето разделяне, вие превръщате всяка цифра в отделен низ. Вече имате 600M струни и всичко свързано с това. Като минимум търсите поне 16 байта на низ, тъй като той съхранява указателя към основния масив, отместване в масива и дължината на низа. За щастие, разделянето всъщност ще използва повторно основния масив, но това наистина не е от голяма полза тук.

16 байта * 600M е 9,6GB.

Определено сега се насочваме към "нелепата" сфера на изискванията за памет.

Не казвате какво всъщност искате да направите. Искате да "заредите файла", но не казвате в какво. Така че е трудно да се даде препоръка как трябва да се направи. Ако искате просто да отпечатате файла, тогава можете просто да прочетете всеки знак един по един и да го отпечатате, но това очевидно не е целта.

Така че, докато, да, можете да "хвърлите памет" върху този проблем, не искате. Трябва да проучите проблема и да излезете с по-добро представяне на това, което се опитвате да постигнете, и да работите от там.

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 MB. След това създавате изцяло нов масив от низове. Това означава, че създавате String указател за всеки char в масива. Въз основа на вашата архитектура това може да бъде 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 MB. Той създава 600 000 000 String обекта, всеки с тегло много повече от 1B... - person amit; 17.04.2014