46 Stimmen

Was macht den heißen Einsatz zu einem "schwierigen Problem"?

Bei der Arbeit haben wir ein Problem mit " PermGen hat keinen Speicher mehr "Der Teamleiter entschied, dass es sich um einen Fehler in der JVM handelte - etwas, das mit dem Hot-Deployment von Code zusammenhing. Ohne viele Details zu erläutern, wies er darauf hin, dass Hot-Deployment ein "schwieriges Problem" sei, so schwierig, dass es sogar in .NET noch nicht möglich sei.

Ich habe viele Artikel gefunden, in denen der Einsatz von Heißluft aus der Vogelperspektive erklärt wird, aber es fehlt immer an technischen Details. Kann mir jemand eine technische Erklärung geben und erklären, warum Hot Deployment "ein schwieriges Problem" ist?

60voto

Eddie Punkte 52504

Wenn eine Klasse geladen wird, werden verschiedene statische Daten über die Klasse in PermGen gespeichert. Solange eine Live-Referenz auf diese Klasseninstanz existiert, kann die Klasseninstanz nicht garbage collected werden.

Ich glaube, dass ein Teil des Problems damit zu tun hat, ob der GC alte Klasseninstanzen aus Perm Gen entfernen sollte oder nicht. Normalerweise werden bei jedem Hot-Deployment neue Klasseninstanzen zum PermGen-Speicherpool hinzugefügt, und die alten, nun unbenutzten, werden normalerweise nicht entfernt. Standardmäßig führen die Sun JVMs keine Garbage Collection in PermGen durch, aber dies kann mit optionalen "java" Befehlsargumenten aktiviert werden.

Wenn Sie also oft genug einen Hot-Deployment-Vorgang durchführen, wird der PermGen-Speicherplatz irgendwann erschöpft sein.

Wenn Ihre Webanwendung nicht heruntergefahren wird vollständig wenn die Bereitstellung aufgehoben wird - wenn z. B. ein Thread weiterläuft -, dann werden alle von dieser Webanwendung verwendeten Klasseninstanzen im PermGen-Bereich angeheftet. Sie stellen erneut bereit und haben nun eine weitere Kopie all dieser Klasseninstanzen in PermGen geladen. Sie heben die Bereitstellung auf und der Thread läuft weiter, wodurch ein weiterer Satz von Klasseninstanzen in PermGen angeheftet wird. Sie stellen erneut bereit und laden einen ganzen Netzsatz von Kopien... und schließlich ist Ihr PermGen voll.

Sie können dies manchmal beheben, indem Sie:

  • Übergabe von Befehlsargumenten an eine neuere Sun JVM zur Aktivierung von GC in PermGen und von Klassen. Das ist: -XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled
  • Verwendung einer anderen JVM, die kein PermGen mit fester Größe verwendet oder die GC für geladene Klassen durchführt

Aber das wird helfen nur wenn Ihre Webanwendung vollständig und sauber heruntergefahren wird und keine Live-Referenzen auf eine der Klasseninstanzen einer Klasse, die von den Klassenladern für diese Webanwendung geladen wurde, zurückbleiben.

Auch dies wird das Problem nicht unbedingt beheben, da der Klassenlader undicht ist. (Sowie zu viele internierte Strings in einigen Fällen.)

Unter den folgenden Links finden Sie weitere Informationen (die beiden fettgedruckten Links enthalten schöne Diagramme, die einen Teil des Problems veranschaulichen).

6voto

OscarRyz Punkte 189898

Das Problem im Allgemeinen ist das Sicherheitsmodell von Java, das eigentlich zu verhindern versucht, dass eine bereits geladene Klasse erneut geladen wird.

Natürlich hat Java von Anfang an das dynamische Laden von Klassen unterstützt, was aber schwierig ist, ist das Nachladen von Klassen.

Es wurde als schädlich angesehen (und das aus gutem Grund), dass eine laufende Java-Anwendung mit einer neuen Klasse mit bösartigem Code injiziert wurde. Zum Beispiel eine geknackte java.lang.String-Implementierung aus dem Internet, die, anstatt einen String zu erstellen, eine zufällige Datei löscht, während sie die Methode length() aufruft.

Die Art und Weise, wie Java konzipiert wurde (und ich nehme an, dass dies auch für die .NET CLR gilt, da sie stark von den JVMs "inspiriert" wurde), sollte verhindern, dass eine bereits geladene Klasse erneut von derselben VM geladen wird.

Sie boten einen Mechanismus an, um diese "Funktion" außer Kraft zu setzen. Klassenlader, aber auch hier waren die Regeln für die Klassenlader, dass sie den "übergeordneten" Klassenlader um Erlaubnis bitten sollten, bevor sie versuchen, eine neue Klasse zu laden; wenn der übergeordnete Klassenlader die Klasse bereits geladen hat, wird die neue Klasse ignoriert.

Ich habe zum Beispiel Classloader verwendet, die eine Klasse aus LDAP oder RDBMS laden

Der Hot-Deploy wird zu einer Notwendigkeit in der Java-Welt, wenn der Anwendungsserver zum Mainstream für Java EE wird (und auch die Notwendigkeit für Mikrocontainer wie Spring schafft, um diese Art von Belastung zu vermeiden).

Der Neustart des gesamten App-Servers nach jeder Kompilierung macht jeden verrückt.

So App-Server-Anbieter, bieten diese "benutzerdefinierte" Class Loader, um heiße Bereitstellung zu helfen, und mit einer Konfigurationsdatei, dieses Verhalten, SOLLTE deaktiviert werden, wenn in der Produktion festgelegt. Aber der Kompromiss ist, müssen Sie Tonnen von Speicher in der Entwicklung zu verwenden. Also der gute Weg, dies zu tun ist Neustart alle 3 - 4 Bereitstellungen.

Bei anderen Sprachen, die von Anfang an darauf ausgelegt waren, ihre Klassen zu laden, ist dies nicht der Fall.

In Ruby zum Beispiel können Sie sogar Methoden zu einer laufenden Klasse hinzufügen, eine Methode zur Laufzeit überschreiben oder sogar eine einzelne Methode zu einem einzelnen spezifischen Objekt hinzufügen.

Der Kompromiss in dieser Art von Umgebungen ist natürlich der Speicher und die Geschwindigkeit.

Ich hoffe, das hilft.

EDIT

Ich habe vor einiger Zeit dieses Produkt gefunden, das verspricht, das Nachladen so einfach wie möglich zu machen. Ich erinnerte mich nicht an den Link, als ich diese Antwort zum ersten Mal schrieb, und ich tue.

Sie ist JavaRebel von ZeroTurnaround

3voto

Vladimir Dyuzhev Punkte 17849

Sun JVM hat PermGen-Speicherplatz festgelegt, und schließlich ist er ganz aufgebraucht (ja, offenbar aufgrund eines Fehlers im Classloader-bezogenen Code) => OOM.

Wenn Sie die JVM eines anderen Anbieters (z.B. Weblogic) verwenden können, wird der PermGen-Raum dynamisch erweitert, so dass Sie nie permgen-bezogene OOM erhalten.

0voto

Ron Punkte 1862

Welche Version von Java verwenden Sie? In der frühen Sun-Version 1.4.2 gab es Bugs, aber sie funktioniert schon seit langer Zeit.
Übrigens, wie werden Sie Ihrem Teamleiter die Nachricht überbringen? Sind Sie der Teamleiter?

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X