Was verursacht PermGen OutOfMemoryError auf JBoss?

8

Was ist die zugrunde liegende Ursache für einen PermGen OutOfMemoryError in JBoss?

Ich führe JBoss AS 4.2.2 in meiner Entwicklungsumgebung aus. Dies geschieht nach mehrmaliger erneuter Bereitstellung meiner Webanwendung.

Der Blog von Christian Vest Hansen bietet JVM-Optionen, die viel helfen , aber das Problem nicht vollständig lösen:

-XX:+UseConcMarkSweepGC
-XX:+CMSPermGenSweepingEnabled
-XX:+CMSClassUnloadingEnabled
-XX:MaxPermSize=128m
Peter Hilton
quelle

Antworten:

5

Wie bereits erwähnt, treten wahrscheinlich undichte Klassenlader auf. Aus irgendeinem Grund werden Ihre Klassen nicht entladen. Dies kann aus zwei Gründen geschehen

  • Objekte dieser Klassen sind noch auf dem Heap vorhanden, Objekte verweisen immer auf ihre Klasse oder
  • Der Klassenlader wird irgendwo referenziert, aus welchem ​​Grund auch immer, Klassenlader verweisen auf ihre Klassen, um sie nicht zweimal zu laden

Es gibt keine umfassende Lösung für dieses Problem. Ein hilfreiches Tool zum Auffinden der Hauptursache ist das Eclipse Memory Analyzer-Tool , das Sie auf einen Heap-Dump aus Ihrer JVM anwenden können (Sie können Heap-Dumps in OOMs mit der Option -XX: + HeapDumpOnOutOfMemoryError aktivieren). Suchen Sie möglicherweise in Ihrer Web-App nach java.lang.Class-Objekten, um festzustellen, warum sie am Leben bleiben. Leider ist PermGen normalerweise nicht Teil eines JVM-Heap-Dumps, so dass Sie nur versuchen können, korrelierende Artefakte im Rest des Heaps zu finden (Klassenobjekte werden nicht in PermGen gespeichert, wenn ich mich nicht irre, nur der tatsächliche Bytecode ist, bitte korrigiere mich, wenn ich falsch liege).

HTH.

Bearbeiten:
Dave Cheney schlägt in einem Kommentar vor, dass java.lang.Class-Objekte tatsächlich Teil von PermGen sind und nicht in einem normalen Hotspot-Heap-Dump enthalten sind. Sofern Sie keine JVM haben, die diese Informationen in den Heap-Dump schreibt, benötigen Sie einen anderen Ansatz. Sie können immer noch nach Instanzen Ihrer Objekte suchen, aber wenn Sie Klassen / Klassenlader verlieren (beide implizieren sich leider gegenseitig), müssen Sie anscheinend nach anderen Zeichen suchen (Metadatenobjekte von JBoss usw.).

falstro
quelle
1
Ich bin mir ziemlich sicher, dass Klassenobjekte im PermGen gespeichert sind (dh Objekte, die Instanzen der Klasse sind). In der Sun JVM gibt es einen separaten Bereich namens Code Cache, in dem Code gespeichert wird, der zu Maschinencode kompiliert wurde. Sowohl der PermGen als auch der Code-Cache sind Teil des Nicht-Heap-Speichers, den Sie mit Tools wie jconsole
Dave Cheney
@ Dave Cheney: Du hast recht. Die durchgesickerten Class-Objekte, die in PermGen stecken bleiben, sind normalerweise die Ursache für das OP-Problem.
Eddie
roe, obwohl ich nicht glaube, dass der Inhalt des PermGen in den Heap-Dump geschrieben ist (dies verwendet die Sun JVM, ich habe nicht viel Erfahrung mit den anderen), weiß das hprof-Dump-Format sicherlich Dinge wie, wie viele Klassen wurden geladen, wie viele Klassenlader usw. Sie können dies sehen, wenn Sie das hprof in Eclipse Memory Analyzer öffnen. Was wahrscheinlich nicht geschrieben wird, sind die großen binären Klassendaten, aus denen der Java-Bytecode besteht. Was Sie im Heap-Dump sehen, ist der 'Stub' der auf dem PermGen gespeicherten Klasseninstanz.
Dave Cheney
2

Die zugrunde liegende Ursache sind Verweise auf Klassen, die verworfen wurden und außerhalb ihres Klassenladeprogramms lecken, wodurch verhindert wird, dass die JVM diese Klassen aus dem Perm entlädt. Diese Flags , die Sie verwenden , um die JVM zu aggressiv Säuberung Klassen verursachen, sind unloadable, aber es wird das zugrunde liegende Problem nicht lösen.

Es gibt eine gute, abeit komplexe Erklärung hier

Dave Cheney
quelle
1

Die Ursache für den PermGen OutOfMemory-Fehler ist die erneute Bereitstellung der App. Die zugrunde liegende Ursache sind durchgesickerte Klassenobjekte in PermGen aus den erneuten Bereitstellungen.

Die Problemumgehung besteht natürlich darin, die JVM nach einer bestimmten Anzahl von erneuten Bereitstellungen neu zu starten.

Dies ist ein sehr schwer zu lösendes Problem, obwohl Sie mit einigem Hin und Her oft große Verbesserungen erzielen können. Hier fangen Sie an: Wenn Ihre Web-App gestoppt ist, stellen Sie Folgendes sicher:

  • Alle von Ihnen gestarteten Threads werden gestoppt
  • Alle von Ihnen gestarteten ThreadPools werden heruntergefahren
  • Alle statischen Referenzen, die Sie freigeben können, werden freigegeben

Dies sind einige der Dinge, die dazu führen können, dass ein Klassenobjekt in PermGen eingeschlossen wird.

Beachten Sie außerdem, dass nicht alle JVMs (oder alle Versionen von JVMs) GC-Klassenobjekte in PermGen verwenden. Wenn Sie eine JVM oder eine Version einer JVM ausführen, die keine Objekte der GC-Klasse in PermGen enthält, können Sie die JVM nach einer bestimmten Anzahl von Neubereitstellungen nur neu starten. Dies trifft angesichts der von Ihnen erwähnten JVM-Optionen wahrscheinlich nicht auf Sie zu.

Eddie
quelle