Schlagwort-Archive: notebook

Java: Falscher ResultSet.getter verursacht Memory Leak

Ich bin ein Gänseblümchen im Sonnenschein
und durch meine Blüte fließt die Sonne in mich rein
Ich bin ein Gänseblümchen und mir wird ganz warm
ich könnt die ganze Welt und dann mich selbst umarmen.
Ich bin ein Gänseblümchen ohne Aggression
Wut, Ärger – was bringt das schon?

JavaDurchatmen, Freakcommander! Momentan gehst du durch die harte Schule einer dir immer noch relativ unbekannten Sprache. Da fällt man mal hin und muss wieder aufstehen, ansonsten wird das nichts.

Die Vorgeschichte

Aber man muss zugegeben, dass der heutige Fehler nicht ganz so leicht zu finden war:

  • Ich habe die Klasse Host umgeschrieben. Vorher hat sie einfach per Methode .toDB() ihre Attribute in die Datenbank geschrieben. Nach dem Umschreiben soll sich die Klasse nur dann in die Datenbank schreiben, wenn sie entweder noch nicht in der DB ist oder ein Attribut sich verändert hat und die DB somit aktualisiert werden muss.
    Grund für das Umschreiben: Innerhalb eines Programmaufrufs werden hintereinander Millionen Instanzen erzeugt und geguckt, ob sie sich verändert haben. Wenn das der Fall ist, muss der Eintrag auch in der DB aktualisiert werden. Da aber UPDATE oder INSERT-Befehle teurer sind und nur ein sehr kleiner Teil der Millionen Einträge sich auch wirklich verändern, macht eine Überprüfung, ob ein UPDATE oder INSERT erfolgen muss, definitiv Sinn.
  • Wie bin ich vorgegangen?
    1. Eine Methode .getFromDB, die die „alten“ Daten aus der DB liest
    2. Eine Methode .equals, die eine Instanz des Objekts mit einer anderen Instanz vergleicht und TRUE zurück gibt, wenn die Attribute gleich sind
    3. Die alte Methode .toDB() dementsprechend angepasst. Einziges Manko war, dass ich in dieser Methode eine Instanz des eigenen Objektes anlegen musste – diese angelegte Instanz des eigenen Objekts bekommt mittels .getFromDB() die alten Daten verabreicht und wird dann mit .equals verglichen.
  • Das Anpassen des Quellcodes war schnell erledigt. Das große Problem war nun allerdings, dass die Anwendung jetzt ein Speicherleck hatte. Der benutzte Speicher wuchs und wuchs und endete schließlich in einer Exception.
  • Anstatt mich direkt mit dem Code zu beschäftigen und durch auskommentieren und System.out.println-Meldungen dem Problem auf die Schliche zu kommen, beschäftigte ich mich mit der Literaturrecherche zu Memory Leaks, Speicherlecks, Garbage Collector und Eclipse Memory Analyzern oder VisualVM, einem Tool, das eine Realtime Heap-Usage Analyse verspricht.
  • Beim Eclipse Memory Analyzer funktionierte das Generieren der .hprof-Datei nicht, die man braucht, um den Analyzer einzusetzen.
  • Und die VisualVM ist sicherlich ein tolles Tool, aber mein uralt Notebook, welches zu wenig RAM und CPU-Leistung hat, arbeitet so langsam mit der VisualVM, dass beim Start schon der Java-Prozess mit meiner Anwendung, die den Memory Leak hat, verschwunden war. So konnte ich leider keinen Memory-Monitorer einschalten oder den Heap dumpen.. No chance.
  • Und nach stundenlanger Recherche und antesten etlicher Tools, um einem Speicherleck in Java zu begegnen, bekam ich schon wieder dieses Gefühl: Wie kann es sein, dass eine Programmiersprache, die millionenfach eingesetzt wird, kein einfach zu installierendes Tool hat, welches automatisch die Daten sammelt, um einem dann vorzuschlagen, welche Klassen oder Methoden man sich nochmal genauer anschauen sollte, um das Speicherleck zu schließen. Wenn in Foren ein Programmierer Probleme mit einem Tool hat, wird ihm einfach ein anderes Tool empfohlen, welches ähnlich ist und bei ihm laufen sollte. Na ja, ich hatte keinen Bock mehr mich durch irgendwelche Seiten und Tools zu klicken.
  • Das Problem war an irgendeiner Stelle in meinem Code, also finde ich einfach die Stelle und behebe das Problem.
  • Nachdem ich sichergestellt hatte, dass sämtliche Statements, PreparedStatements, ResultSets und Connections nach getaner Arbeit auch wieder geschlossen wurden und das Problem nach wie vor auftrat, kümmerte ich mich um die Instanz, die innerhalb der .toDB()-Methode erzeugt wird. Vielleicht werden ganz viele Instanzen erzeugt, die der Garbage Collector aus irgendwelchen Gründen nicht löschen kann. Aber auch daran lag es nicht.
  • Schließlich ging ich dazu über ganze Funktionen und Programmteile auszukommentieren. Folgender Programmcode verursachte das Speicherleck

Der Fehler

In der Methode .getFromDB(), die einfach nur per DB-Query Daten einliest, gab es folgende 3 Zeilen Code, die Grund für das Memory Leak waren:

[code lang=’java‘]this.setM_swap(rs.getInt(16));
this.setD_total(rs.getInt(17));
this.setD_free(rs.getInt(18));[/code]

Aus dem ResultSet der DB-Abfrage werden per Setter-Methoden die Attribute gesetzt. Das Problem? Da die Java-Datentypen und die DB-Felder für m_swap, d_total und d_free mit Integer bzw. int nicht ausreichend lang waren, habe ich sie nachträglich auf long bzw. Bigint (DB) geändert. Dabei habe ich auch die setter wie setM_swap() so geändert, dass sie als Parameter long erwarten.  Normalerweise schreit ja gleich das IDE los, wenn ein Typ nicht passt, aber Java findet (und in diesem Fall völlig zu Recht), dass Methoden, die long als Parameter erwarten, auch mit int gefüttert werden können und hat deswegen nicht gemeckert.

Das Memory Leak kann ich mir nur so erklären, dass mit rs.getInt auf eine Spalte zugegriffen wurde, welche in der Datenbank als BigInteger definiert ist.

Richtigerweise hätte man mit rs.getLong() arbeiten müssen, dann gibt es auch keine Probleme mit dem Speicher. ;)

Asus Service – Die Null bleibt stehen

Ihr kennt doch bestimmt diese tollen Firmenmail-Footer, wo nochmal die Anschrift, Mailadresse und Telefonnummer drin steht, oder? Schön verziert mit dem Firmenlogo und irgendeinem tollen Slogan. Bei Asus-Mitarbeitern steht dort der Slogan

About ASUS:
The Asus Winning Formula:
Winning = Marketing(Quality*Speed*Innovation*Service)/Cost

Ins Deutsche übersetzt (schließlich gilt „Wir sind hier in Deutschland„):

Über Asus:
Die ASUS Gewinnformel:
Gewinn = Marketing(Qualität*Geschwindigkeit*Innovation*Service)/Kosten

Mir ist jetzt nicht so ganz klar, worauf sich Speed/Geschwindigkeit bezieht, aber wenn der Service eine 0 ist, dann sollte auch die Asus Gewinnformel Null werden.

Ich würde nie wieder einen Computer von Asus kaufen und das liegt alleine an folgenden Umständen:

  1. mein Notebook ist seit dem 21.07. bei Asus in Reperatur
  2. mir wurde zwar nach einem Monat eine Gutschrift angeboten, diese kann ich laut Asus aber nicht in Anspruch nehmen, weil der Händler in Insolvenz gegangen ist (das Notebook habe ich bei einem Händler namens e-bug bei Amazon gekauft, damals hieß der Händler „BUG Computer Components AG„. Die Domain e-bug.de wurde dann von der „Computer Components GmbH“ übernommen. Ein Schelm, wer Böses dabei denkt…)
  3. Asus reagierte auf meine Mail nicht, in der ich um Auskunft bat, bis wann sie die Reparatur abgeschlossen haben
  4. Ich setzte eine zweiwöchige Frist, in der sie mir Auskunft geben sollten. Diese Frist verstrich.
  5. Erst nach einem Anruf bekam ich eine Mail, dass die Reparatur weitere 3-4 Wochen in Anspruch nehmen würde.
  6. Diese 4 Wochen verstrichen erneut ohne Reaktion. Ich telefonierte mit Asus.
  7. Ich bekam eine Mail mit der Aussage, dass auf ein Ersatzteil gewartet wird, welches frühestens am 25.10. bei Asus eintreffen wird. Frühestens.. *haha*
  8. Ich schrieb Asus erneut eine Mail, dass es ja wohl absolut inakzeptabel sei, dass man über 3 Monate auf die Reparatur warten muss. Ich setzte eine allerletzte Frist bis zum 09.11., in der ich mit einem Anwalt drohte.

[youtube CLfzfC3JXAw]

Und jetzt ist die letzte Frist fast abgelaufen und ich muss mir Gedanken machen, ob ich einen Anwalt für *** EUR beauftrage gegen ASUS vorzugehen. Ich würde ja gerne ein solches Serviceverhalten durch einen Anwalt abstrafen lassen, aber ich glaube, ich spare lieber das Geld, lasse hier meine Wut raus und gestalte die ASUS Gewinnformel durch mein schädliches Word of Mouth-Marketing noch etwas negativer! Suckers!