Speicherlecks in Java EE-Anwendungen
Es gibt verschiedene Arten von Speicherlecks, z. B. Thread- und ThreadLocal-Lecks, Klassenladerlecks, Systemressourcenlecks und Verbindungslecks. Die Methoden zur Erkennung von Speicherlecks beinhalten in der Regel eine Überprüfung von JVMTI- (Java™ Virtual Machine Tool Interface) oder PMI-Zählern (Performance Monitoring Infrastructure), um eine langsame Zunahme der Java-Heapspeicherbelegung oder der nativen Heapspeicherbelegung zu überwachen.
Speicherlecks in Klassenladern
Viele Speicherlecks zeigen sich als Klassenladerlecks. Eine Java-Klasse wird durch ihren Namen und den Klassenlader, durch den sie geladen wurde, eindeutig identifiziert. Klassen mit demselben Namen können mehrfach in einer einzelnen JVM geladen werden, jeweils in einem anderen Klassenlader. Jede Webanwendung erhält einen eigenen Klassenlader, sodass WebSphere Application Server Anwendungen eingrenzen kann.
Ein Objekt behält einen Verweis auf die Klasse bei, in der es eine Instanz ist. Eine Klasse behält einen Verweis auf den Klassenlader bei, durch den sie geladen wurde. Der Klassenlader behält einen Verweis auf jede Klasse bei, die er geladen hat. Durch das Beibehalten eines Verweises von einer Webanwendung auf ein einzelnes Objekt wird jede von der Webanwendung geladene Klasse im Speicher belassen. Diese Verweise bleiben häufig nach dem erneuten Laden einer Webanwendung erhalten. Mit jedem erneuten Laden werden mehr Klassen im Speicher belassen, wodurch es zu einem Fehler aufgrund abnormaler Speicherbedingungen kommt.
Speicherlecks in Klassenladern werden normalerweise durch den Anwendungscode oder den JRE-Code verursacht.
Durch JRE ausgelöste Speicherlecks
Speicherlecks treten auf, wenn JRE-Code (JRE - Java Runtime Environment) mit dem Kontextklassenlader ein Anwendungssingleton lädt. Diese Singletons können Threads oder andere Objekte sein, die von JRE mithilfe des Kontextklassenladers geladen werden.
- Der Kontextklassenlader wird zum Webanwendungsklassenlader.
- Ein Verweis auf den Webanwendungsklassenlader wird erstellt. Für diesen Verweis wird nie eine Garbage-Collection durchgeführt.
- Der Klassenlader und alle von ihm geladenen Klassen werden im Speicher belassen.
Durch die Anwendung ausgelöste Speicherlecks
- Angepasste Klasse ThreadLocal
- Webanwendungsklasseninstanz als ThreadLocal-Wert
- Indirekt durch einen ThreadLocal-Wert gesperrte Webanwendungsklasseninstanz
- ThreadLocal-Pseudoleck
- ContextClassLoader und Threads, die durch Webanwendungen erstellt werden
- ContextClassLoader und Threads, die durch Klassen erstellt werden, die vom allgemeinen Klassenlader geladen werden
- Variablen für statische Klassen
- JDBC-Treiberregistrierung: RMI-Ziele
WebSphere Application Server verfügt jetzt über einige Mittel zum Schutz vor Speicherlecks, wenn Anwendungen gestoppt oder erneut implementiert werden. WebSphere Application Server überwacht die Anwendungs- und Modulaktivität und führt Diagnoseaktionen aus, wenn eine Anwendung oder ein einzelnes Modul gestoppt wird.
- Erkennung: Warnungen ausgeben, wenn ein Speicherleck festgestellt wird. Durch eine Kombination von Standard-API-Aufrufen und einigen Reflexionstricks, wenn eine Webanwendung gestoppt, deimplementiert oder erneut geladen wird. WebSphere Application Server sucht nach bekannten Ursachen von Speicherlecks und gibt Warnungen aus, wenn ein Speicherleck festgestellt wird:
[11/17/11 12:01:05:911 EST] 00000005 LeakDetection E CWMML0015E: Die Webanwendung [WasSwat#WasSwatWeb.war] hat einen ThreadLocal mit einem Schlüssel des Typs [test.memleak.MyThreadLocal] (Wert [test.memleak.MyThreadLocal@216c691]) und dem Wertetyp [test.memleak.MyCounter] (Wert [test.memleak.MyCounter@21942ff]) erstellt, konnte diesen aber nicht entfernen, als sie gestoppt wurde.
- Die Verhinderung ist standardmäßig aktiviert und betrifft nur durch JRE ausgelöste Speicherlecks. Durch JRE ausgelöste Speicherlecks werden durch die Initialisierung von Singletons während des Serverstarts vermieden, wenn der Klassenlader des Anwendungsservers der Kontextklassenlader ist.
- Behandlung: Führen Sie proaktive Schritte zur Behebung von Speicherlecks aus. Diese Maßnahmen haben angemessene Standardwerte und werden fallorientiert konfiguriert.
protected void com.ibm.ws.classloader.clearReferences(){ if(ENABLE_CLEAR_REFERENCES_JDBC) clearReferencesJdbc(); if(ENABLE_CLEAR_REFERENCES_THREADS) clearReferencesThreads(); if(ENABLE_CLEAR_REFERENCES_THREADLOCALS) clearReferencesThreadLocals(); if(ENABLE_CLEAR_REFERENCES_RMI_TARGETS) clearReferencesRmiTargets(); if(ENABLE_CLEAR_REFERENCES_STATICS) clearReferencesStaticFinal(); }
Ursache des Speicherlecks | Korrekturmaßnahmen | Eigenschaften von WebSphere Application Server Java Virtual Machine für die Aktivierung und Steuerung |
---|---|---|
Threadlocal | Erneuern Sie Threads im Thread-Pool über einen konfigurierbaren Zeitraum. Das Abrufen von Threads aus dem Pool ermöglicht die Durchführung einer Garbage-Collection für die Threads und Threadlocals. |
|
HTTP-Client-Keepalive-Threads | Wechseln Sie den Thread zum übergeordneten Klassenlader. |
|
Zeitgeberthreads | Verwenden Sie Reflexion, um alle neuen Tasks zu stoppen, die möglicherweise geplant sind. |
|
Nicht JVM-gesteuerte Threads | Wenn der Thread über ein Steuerprogramm gestartet wird, beenden Sie das Steuerprogramm oder unterbrechen Sie den Thread. |
|
JDBC-Treiber | Heben Sie die Registrierung aller JDBC-Treiber auf, die von der Webanwendung registriert wurden und die die Webanwendung übergangen hat. |
|
Ressourcenpaket | Löschen Sie alle Pakete aus dem Ressourcenpaketcache (ResourceBundle), die von diesem Klassenlader oder einem beliebigen anderen Klassenlader, dem dieses Ladeprogramm übergeordnet ist, geladen wurden. |
|
RMI-Ziele | Löschen Sie die Werte in sun.rmi.transport.ObjectTable.implTable und sun.rmi.transport.ObjectTable.objTable mithilfe von Reflexion. |
|
Variablen für statische Klassen | WebSphere Application Server setzt den Wert aller Variablen für statische Klassen der Klassen, die vom Anwendungs- oder Modulklassenlader geladen werden, auf einen Leerwert. |
|