Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
Was genau bedeuted das? Also klar der Speicher reicht nicht hin. Ich bearbeite da ein Array mit gut 80 Spalten und 5000 Zeilen. Wie kann ich das messen ob der Speicher reicht etc? Ich kann mir auch nicht ganz vorstellen, dass 512MB RAM nicht reichen, und ich weiß auch nicht wofür "heap space" steht.
danke für die Erläuterung. Ich frage nochmal anders herum, ich habe praktisch eine Schleife im Programm, die 6 mal das gleiche macht: immer Daten laden in ein Array packen und dann analysieren.
1) Dieses Problem müßte dann ja bei vielen vorkommen, denn sooooo riesig sind die Datenmengen ja auch nicht oder? Ich meine ein Array 89*5000 ist nicht klein, aber das kann ja nicht Java sprengen oder?
2) Gibts es da noch andere Möglichkeiten? ich denke gerade daran, ob es Sinn machen würde den Garbage Collector extra irgendwie anzuwerfen? Obwohl eingentlich macht er das ja auch ganz ordentlich...
Ich probiere deinen Tipp mal aus!
EDIT: also selbst mit 512mb (ich übergebe das Argument in Eclipse) geht das nicht. Ist für mich jetzt schwer vorstellbar, dass es net geht. Was kann man da sonst noch machen bzw. überprüfen?
Was steht denn im Array? Was für Objekte sind das?
Garbage Collector anwerfen nützt nichts, der kommt automatisch. Du könntest mal überlegen ob du deinen Algorithmus so umschreiben kannst, dass du keine Arrays mehr benötigts.
>>immer Daten laden in ein Array packen und dann analysieren.
machst du jedesmal ein neues Array (oder doch lieber das vorhandene wiederverwenden)? denn dann wären wir ja schon bei
6 x 89 x 5000, also ungefähr 2,7 Millionen ArrayEinträge: stellt sich die Frage von welchem Typ die Einträge sind...
@Beni: In meinem Array stehen nur Strings drin, die werden aus einer Tabdatei eingelesen.
@Bleiglanz: Du hast Recht, es wird jedesmal ein neues Array erzeugt. Ich habe nur erwartet - weil nach dem Durchlauf nichts mehr auf das Array verweist - dass es automatisch dann per Garbage Collector entfernt wird.
Ablauf ist wie folgt:
- Datei einlesen --> Array draus machen --> berechnen ---> Werte schreiben
- neue Datei einlesen --> neues Array machen (kann unterschiedlich groß sein) --> berechnen --> Werte schreiben
- ... und das sechs mal
Es ist also nie das gleiche Array, da es nach der Analyse auch wieder in eine Datei geschrieben wird, dürfte da doch keine Referenz mehr drauf sein und müßte "entsorgt" werden, oder?
Ein Array finde ich da praktisch, damit habe ich eine Matrix und kann bequem mit rechnen. Was soll man sonst nehmen? ArrayList ist doch intern auch nur Array und geht doch bestimmt noch mehr in Speicher, oder?
Also 5 Ziechen haben die immer! Es sind auch ein paar Werte die weniger haben, aber auch wiederum viele die mehr haben. Ich Durchschnitt liege ich über 5 Zeichen.
Was an Code soll ich mal rausstellen? In Summe ist das schon ziemlich viel.
Ich habe eine "Oberklasse" die die ganzen Analysemethoden bereitstellt. Dann erstelle ich eine gewisse Anzahl von Objekten (je nachdem was ich betrachten will), jedes ist von der Oberklasse abgeleitet. Die nudelt das Programm dann hintereinander ab.
1) Ja ich lese das zeilenweise mit BufferedReader (readline()) und StringTokenizer ein
2) Kann man schnell feststellen ob noch irgendeine Referenz auf das Objekt ist? Das sind in Summe knappe 4000 Zeilen Code, wo ich mich dann durchklicken müßte...bleibt aber nix anderes über oder?
Nur aber zum richtigen Verständis, wie würde konkret eine Referenz aussehen? Oder was wäre typisch, dann könnte ich direkt mal suchen. Irgendein Automatismus wäre cool
Ich versuche aber das schonmal darszustellen:
Also Array wird gelesen und dann weiß ich die Größe also:
Code:
alleDaten = new String[getAnzahlDerZeilen()][getAnzahlDerSpalten()];
danach lese ich die Datei dann wirklich und jetzt passt sie ja auch ins Array genau rein:
Das steht halt in einer Klasse drin, wovon ich ein Objekt erzeuge wenn der erste Durchlauf startet. Wenn dann der nächste Durchlauf startet, greife ich auf die Daten vom ersten Durchlauf gar nicht mehr zurück, denn die werden am Ende des Durchgangs ja auch geschrieben. Beim zweiten Durchlauf wird von der Klasse dann ein neues Objekt erzeugt und so weiter...
ersetz erstmal den StringTokenizer durch String#split, so wie es in deinem zweiten Codefragmet steht??
und
Code:
alleDaten = new String[getAnzahlDerZeilen()][getAnzahlDerSpalten()];
das ist komisch: woher weisst du vor dem einlesen, wieviele Zeilen in der Datei drin sind? liest du zweimal?
mach lieber eine ArrayList<String[]>, dann brauchst du vorher nicht wissen wieviele Zeilen kommen
interessant ist
Code:
alleDaten = new String[getAnzahlDerZeilen()][getAnzahlDerSpalten()];
// dann befüllt
setAlleDaten(alleDaten);
reader.close();
// was kommt danach? das methodenende?
// ist "alleDaten" einen lokale Variable
1) Ja ich lese zweimal, einmal um Arraygröße zu bestimmen, zweites mal um das einzutüten. Hab das mit der ArrayList nie so richtig hinbekommen, die muss dann ja noch zweidimensional sein. Verbracuht das aber erst Recht nicht noch mehr Speicher?
2) also alleDaten ist für die Klasse global, also für alle Methoden aus der Klasse sichtbar. Danach ist das Methodenende und es kommt nix mehr
1) Nein, spar dir das zweimal lesen Nimm einfach eine ArrayList<String[]>, wobei du beim lesen immer add(line.split("\\t")); aufrufst
2) Ist schonmal schlecht: da alleDaten eine Membervariable ist, bleibt nach dem Aufruf von setAlleDaten(alleDaten) ja diese Referenz auf das Array noch übrig
Wenn du beim zweiten Durchlauf "greife ich auf die Daten vom ersten Durchlauf gar nicht mehr zurück" dann eine neue Klasse erzeugst, und die erste noch lebt, dann kann das Array nicht entsorgt werden
Obwohl das Design IMHO schon ziemlich kaputt ist, könnte kurzfristig eventuell ein
Code:
setAlleDaten(this.alleDaten);
reader.close();
this.alleDaten = null; // ausnullen ist meistens ein schlechter Rat
zunächst dochmal nen dickes danke, dass du so lange dabei bleibst - Thx
erste Version hab ich probiert und bekomme NullPointerException .... also doch noch irgendwo ne Referenz drauf.
Die zweite Version kann ich doch gefahrlos einsetzen oder? Durch static muss ja jedes Objekt die gleiche Variable nehmen, dadurch sollte das doch weg sein oder?
Mhhhh hätt ich ja auch mal drauf kommen können :roll: Ich probiers nachher mal gleich aus. Noch eine Frage, da ich ja beim Analysieren dauernd auf das Array zugreife kann ich doch aber dann mit get und set drauf zugreifen oder? Denn würde das das so nehmen wie du geschrieben hast, dann würde er ja jedesmal das Teil runterladen. Das soll ja nur einmal geschehen.
also ich bin gerade am umbaun ;-)
Stellt sich aber noch folgendes Problem mit der toArray() Methode der ArrayList...da bekomme ich kein 2D Array raus, das ist immer nur einfach gefüllt. Ich finde in der Doku auch nur zwei Methoden aber beide geben nur ein 1D Array zurück :roll:
Wie krieg ich Array[][] hin?
Fry
STOPP: Geht irgendwie doch, muss erstmal weiter überprüfen
- ich habe jetzt das ganze Programm nochmal zerpflügt und neu strukturiert (sagen wirs so, alles rausgeworfen und nur noch eine Methode zum Testen übergelassen :lol: )
- ABer: Es tritt immer noch auf. Allerdings habe ich jetzt nochmal die Quelle analysiert. Meine Annahme am anfang war falsch, ich habe im Download mehrere Textfelder, in denen als durchaus einige Zeichen enthalten sein können...mehr als 5 im Durchschnitt auf jeden Fall.
- Eine blöde Frage bleibt aber dennoch....wieso geht das in Excel :roll: da kann ich genau das gleiche kopieren und dann Auswertungen drüberlaufen lassen...und es tut.
- Es ist so ziemlich bei 5000 Zeilen Ende, davor geht alles
EDIT: Ich habe jetzt nochmal etwas rumprobiert und eine interessante Entdeckung gemacht. Ich hab unter gewissen Voraussetzungen möglichkeiten die tab Datei zu beeinflussen. So habe ich das mal getan und jetzt nur noch 12 Spalten.
- die ersten 6 Spaten haben max 14 Zeichen
- die 7. Spalte immer 5
- die 8. max 18 meißt aber weniger
- die 9. und 10. jeweils genau 8
- die 11. nicht mehr als 15
- die 12. auch nicht mehr als 15
Ich habe das mit dem einlesen jetzt so gemacht wie du gesagt hast, und auch im nachhinein probiert nochmal das array = null zusetzen. Hilft aber auch nichts, er ballert immer wieder mit heap space raus. Dieses aber genau immer dann, wenn die Anzahl der Zeilen gegen 5000 geht. Vorher keine Probs.
Also ich gebe diesen Parameter bei Eclipse mit. Bei "Run..." gehe ich dann auf Arguments und trage dort "-Xmx512m" ein.
Ich habe aber noch was herausgefunden. Ich ändere die Einlesedatei (unter gewissen Voraussetzungen kann ich das machen ohne das es das Ergebnis ändert) und dann habe ich zwischen 100 und 700 Zeilen. Und das Programm läuft anstandlos durch. Die Frage ist nur ob sich das irgendwie "anstaut" und dann irgendwann einem wieder um die Ohren fliegt. Ich habe komplett alle Auswertungen herausgenommen und nur noch folgendes drin (nur pseudohaft, da Code auf anderem Rechner...)
Code:
public void testMethod(int id, String[][] allDataArray)
GregorianCalendar cToday = new GregorianCalendar();
GregorianCalendar cCheck = new GregorianCalendar();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
calendar.add(Calendar.MONTH, 1);
ArrayList list = new ArrayList();
list.add(new String(sdf.format(cToday.getTime());
for (int i=1; i<allDataArray.length; i++) // ote zeile nicht betrachten
{
....
if(.....) //hier kommt eine IF Abfrage, die prüft ob in vier Spalten Bedingungen erfüllt sind
{
//Einige Zellen sind Daten, die werden geparst und in den Calender geschrieben
int tag = Integer.parseInt(<entsprechnedeZeile>.toString().substring(0,2)//In Klammer ein bestimmter Wert in einer Spalte wird zerschnippelt und der tag extrahiert
int monat = ...
int jahr = ...
cCheck.set(jahr,monat,tag);
if(cToday.compareTo(cCheck) !=0)
{
//Hier ein paar Prüfungen um was für einen Tag es sich handelt
}
list.add(new String(allDataArray[i][SPALTE]
list.add(new Integer(allDataArray[i][ANDERE_SPALTE]
... (insgesammt häng ich vier Werte pro Durchlauf an die ArrayListe, die ist für gewöhnlich keine 20 Elemente lang)
//Erzeugen einer klasse die das Schreiben vornimmt
objektDerKlasse.schreibe(....);
Wenn ich also die Berechnung machen lasse mit dieser einen Methode und ich habe an die 5000 Zeilen ---> Speicherprob :gaen:
Wenn ich die Berechnung mit vorher eingeschränkter Datei machen ---> läuft durch
Ich glaube auch nicht so Recht dran, dass es nicht wegen des Speichers geht, aber gibt es eine Möglichkeit das herauszufinden wieviel Speicher welches Objekt belegt? Das wäre cool
-Xrunhprof[:help][:<suboption>=<value>,...]
Enables cpu, heap, or monitor profiling. This option is typically followed by a list of comma-separated "<suboption>=<value>" pairs. Run the command java -Xrunhprof:help to obtain a list of suboptions and their default values.
hier nochmal ein richtig dickes Danke an dich. :applaus:
Ich probiere jetzt mit den Einstellungen nochmal herum, und sollte das mit dem heap speicher nochmal auftreten, kann ich das jetzt ein wenig analysieren :### ???:L
Ich werde das Programm jetzt mit deinen Tipps nochmal neu aufbauen und schaun ob es dann klappt!
Ich setzt das jetzt mal auf gelöst, wenn konkrete Probleme gibt kann ich ja dann die Ausgaben der Konsole posten.