2009-08-15 10 views
48

Welche Klassen der Java-Standard-API können Speicherlecks verursachen, wenn sie (nicht offensichtlich) inkorrekt verwendet werden? Und wie können diese Speicherlecks vermieden/behoben werden?Speicherleck-Traps in der Java-Standard-API

Beispiel:ObjectInputStream und ObjectOutputStream halten Verweise auf alle Objekte, die sie um gesehen haben als Referenzen nachfolgende Vorkommen des gleichen Objekts zu senden, anstatt Kopien (und damit umgehen mit zirkulären Referenzen). Dies führt zu einem Speicherverlust, wenn Sie einen solchen Stream unbegrenzt offen halten (z. B. wenn Sie ihn für die Kommunikation über das Netzwerk verwenden).

Fix: Call reset() periodisch oder nach jedem Top-Level-Objekt.

+3

@Michael - vielleicht bewegen Sie Ihr Beispiel zu einer Antwort von selbst? –

Antwort

46

Eine große Sache ist, dass Teilstrings von Java-Strings bezieht sich auf die ursprüngliche Zeichenfolge.

Beispiel: Sie haben einen 3000 Zeichen langen Datensatz gelesen und erhalten eine Teilzeichenfolge von 12 Zeichen, die Sie an den Aufrufer (innerhalb derselben JVM) zurückgeben. Obwohl Sie nicht direkt einen Verweis auf die ursprüngliche Zeichenfolge haben, verwendet diese Zeichenfolge mit 12 Zeichen immer noch 3000 Zeichen im Speicher.

Für Systeme, die viele Nachrichten empfangen und dann analysieren, kann dies ein echtes Problem sein.

Sie haben ein paar Möglichkeiten, dies zu vermeiden:

String sub = new String(str.substring(6,12)); 

oder

String sub = str.substring(6,12).intern(); 

Die erste ist mehr clearcut. Die zweite hat andere Auswirkungen, weil Sie PermGen-Speicherplatz verwenden. Überstrapaziert können Sie ausgehen, wenn Sie Ihrer VM nicht genug geben.

Denken Sie daran, dies ist nur relevant, wenn Sie kleine Teilstrings nehmen und dann die ursprüngliche Saite wegwerfen und Sie tun dies sehr.

+1

Wie wäre es mit einem einfachen Fix wie das explizite Erstellen eines neuen String-Objekts? –

+0

Nicht einen sehr alten Thread zu stoßen, aber was ist der Grund dafür? Warum würde diese Zeile "str = strstring (6,12)" einen Raum von 3k Zeichen verschwenden, anstatt nur 6? –

+2

@Murat: Stoßen einen alten Kommentar: Weil es intern bezieht sich auf die gleiche Char-Array als die ursprüngliche Zeichenfolge, nur mit einem anderen Offset und Länge. Wenn Sie viele überlappende Teilstrings erstellen, wird tatsächlich Speicher gespart. –

4

Jede Klasse mit dispose() Methode?

Zum Beispiel java.awt.Window#dispose:

public void entsorgen()

Releases all nativen Bildschirm Ressourcen durch dieses Fenster verwendet, deren Subkomponenten, und alle von den unternehmenseigenen Kindern. Das bedeutet, dass die Ressourcen für diese Komponenten zerstört werden. Der von ihnen verbrauchte Speicher wird an das Betriebssystem zurückgegeben und als nicht wiedergabebereit markiert.

8

Alles, was Sie als Empfänger eines Ereignisses registrieren, z. In GUI-Frameworks kann nicht als Garbage Collection erfasst werden, solange sie registriert ist und die Ereignisquelle aktiv ist.

Dies kann zu Speicherlecks führen, wenn ein Entwickler diese starke Referenz von der Ereignisquelle nicht an den Ereignisteilnehmer erkennt.

+0

Es ist eine gute Idee, schwache Referenzen für jeden Zuhörer zu verwenden, der länger leben soll als er hört. –

+0

Dies ist fast das Standardbeispiel für ein Speicherleck, weil es offensichtlich ist, aber leicht zu vergessen. –

5

Jede Instanz eines Threads weist Speicher für einen Stack zu (Standard 512k, einstellbar über -Xss).Es ist kein Leck als solches, aber ein naive Versuch, eine Anwendung stark zu multi-thread wird zu einem beträchtlichen nicht offensichtlichen Verbrauch von Speicher führen.

+3

Eigentlich kann es zu einem offenen Leck werden, wenn Sie Thread-Objekte erstellen und nie start() aufrufen - der Stapelspeicher wird dann nie zurückgewonnen, IIRC. –

+0

Interessant. Wusste das nicht. –

+2

@Michael Borgwardt: Ich denke nicht, dass das der Fall ist; Hast du eine Quelle? \ [edit \]: Es sieht so aus, als wäre es ein Fehler in älteren Versionen der JVM, sollte aber in Java 5 behoben sein. – Miles

7

Alle nicht statischen inneren Klassen, die Sie an äußeren Klassen halten. So dass unschuldig aussehende innere Klasse auf einem riesigen Objekt Graphen halten kann. Fügen Sie die Instanz irgendwo in eine statische oder anwendungsweite Sammlung ein und verwenden Sie einen Los Speicher, den Sie nicht verwenden sollten.

3

Verwendung von starken Referenzen, wenn schwache Referenzen ausreichend gewesen wären. Anwendungen und APIs, die ihr eigenes Zustands- und Ressourcenmanagement durchführen, sind hier die üblichen Schuldigen.

Dann gibt es die Verwendung des Beobachter-Muster, die zu Speicherlecks führen könnte - wenn der Beobachter sich aus dem Thema dekotiert, Speicher kann nicht zurückgewonnen werden, wenn der Gegenstand freigibt auch den Verweis auf die Beobachter/Zuhörer. Dies wurde bereits früher erwähnt, aber nicht viele Menschen erkennen, dass selbst Holzfäller Beobachter sind.

Zusätzlich there is the likelihood of classes, whose objects when instantiated are automatically placed into a static member. Einige dieser Klassen verfügen nicht einmal über eine release() - oder eine dispose() -Methode, sodass die Referenzen weiterhin vom statischen Member gehalten werden. Diese Vielzahl von Speicherlecks führt schließlich zu einem OutOfMemory-Fehler mit einem PermGen-Speicherplatzproblem, das als Hauptursache gemeldet wird, was die Diagnose erschwert.

Verwandte Themen