Große Datei in Java lesen - Java-Heapspeicher

7

Ich lese eine große tsv-Datei (~ 40G) und versuche, sie zu beschneiden, indem ich Zeile für Zeile lese und nur bestimmte Zeilen in eine neue Datei drucke. Allerdings bekomme ich immer die folgende Ausnahme:

%Vor%

Unten ist der Hauptteil des Codes. Ich habe die Puffergröße für den Fall 8192 angegeben. Löscht Java den Puffer nicht, wenn die Puffergröße erreicht ist? Ich sehe hier nicht, was den großen Speicherverbrauch verursachen könnte. Ich habe versucht, die Heap-Größe zu erhöhen, aber es machte keinen Unterschied (Maschine mit 4 GB RAM). Ich habe auch versucht, die Ausgabedatei alle X Zeilen zu löschen, aber es half auch nicht. Ich denke, vielleicht muss ich zum GC telefonieren, aber es klingt nicht richtig.

Irgendwelche Gedanken? Danke vielmals. BTW - Ich weiß, ich sollte trim () nur einmal aufrufen, speichern und dann verwenden.

%Vor%     
user431336 04.05.2011, 22:30
quelle

5 Antworten

17

Am wahrscheinlichsten ist, dass die Datei keine Zeilenabbrecher hat und der Leser einfach so lange wächst, bis der StringBuffer nicht mehr ausreicht.

Die Lösung wäre, eine feste Anzahl von Bytes gleichzeitig zu lesen, indem die 'read'-Methode des Lesers verwendet wird und dann nach neuen Zeilen (oder anderen syntaktischen Token) innerhalb der kleineren Puffer gesucht wird.

    
toadaly 04.05.2011 22:37
quelle
3

Sind Sie sicher, dass die Zeilen in der Datei durch Zeilenumbrüche getrennt sind?

    
Steve Emmerson 04.05.2011 22:38
quelle
2

Ich habe 3 Theorien:

  • Die Eingabedatei ist nicht UTF-8, sondern ein unbestimmtes Binärformat, das beim Lesen als UTF-8 zu extrem langen Zeilen führt.

  • Die Datei enthält einige extrem lange "Zeilen" ... oder überhaupt keine Zeilenumbrüche.

  • Etwas anderes passiert im Code, den Sie uns nicht zeigen; z.B. Sie fügen neue Elemente zu set hinzu.

Um die Diagnose zu erleichtern:

  • Verwenden Sie ein Tool wie od (unter UNIX / LINUX), um zu bestätigen, dass die Eingabedatei wirklich gültige Zeilenabschlusszeichen enthält. d.h. CR, NL oder CR NL.
  • Verwenden Sie ein Tool, um zu überprüfen, ob die Datei UTF-8 ist.
  • Fügen Sie Ihrem Code einen statischen Zeilenzähler hinzu, und wenn die Anwendung mit einem OOME explodiert, drucken Sie den Wert des Zeilenzählers aus.
  • Behalte die längste Linie, die du bisher gesehen hast, und drucke sie auch aus, wenn du ein OOME bekommst.

Zur Erinnerung: Ihre etwas suboptimale Verwendung von trim hat keine Auswirkungen auf dieses Problem.

    
Stephen C 04.05.2011 22:44
quelle
1

Eine Möglichkeit besteht darin, dass Ihnen während einer Garbage Collection der Heap-Speicherplatz knapp wird. Die Hotspot-JVM verwendet standardmäßig einen parallelen Kollektor, was bedeutet, dass Ihre Anwendung möglicherweise Objekte schneller zuordnen kann als der Kollektor sie zurückfordern kann. Ich konnte einen OutOfMemoryError mit angeblich nur 10K lebenden (kleinen) Objekten verursachen, indem ich schnell zuordnende und verwerfende.

Sie können stattdessen versuchen, den alten (vor 1.5) seriellen Kollektor mit der Option -XX:+UseSerialGC zu verwenden. Es gibt mehrere andere "erweiterte" Optionen, die Sie zum Abstimmen verwenden können Sammlung.

    
Nathan Ryan 04.05.2011 23:38
quelle
-1

Sie sollten versuchen, die Deklaration String[] fields aus der Schleife zu entfernen. Wenn Sie in jeder Schleife ein neues Array erstellen. Du kannst das alte einfach wiederverwenden?

    
Shaunak 04.05.2011 22:39
quelle

Tags und Links