Ein Bugfix für Tomcats automatisches Herunterfahren

Ein Bugfix für Tomcats automatisches Herunterfahren

Vorwort

Bei einem seit 4 Jahren laufenden Java EE-Webprojekt kam es in letzter Zeit häufig zu der Rückmeldung von Kunden, dass sich das System nicht öffnen lässt. Ich habe mich beim Server angemeldet, um den Dienst zu überprüfen, und festgestellt, dass Tomcat automatisch heruntergefahren wurde. Es passiert grundsätzlich alle 3 bis 4 Tage.

Das Betriebs- und Wartungspersonal dachte zunächst, dass andere Dienste den Tomcat-Dienst beendet hätten, und nahm dies nicht ernst. Die Lösung bestand darin, Tomcat direkt neu zu starten.

Schließlich geriet die Situation außer Kontrolle und die Kunden beschwerten sich über das Betriebs- und Wartungspersonal, woraufhin ihm ein Monatslohn für seine Leistung abgezogen wurde.

Die Lösung für diesen Fehler kam mir nach vielem Hin und Her. Nachdem Sie die Aufgabe erhalten haben, können Sie sich einfach an die Arbeit machen. Es gibt keinen Fehler, der nicht behoben werden kann.

Die Betriebsumgebung des Systems ist wie folgt:

  • Tomcat6.0
  • 32-Bit-JDK 7.0
  • Windows Server 2003 32 Bit, 32 GB Speicher.

Überprüfen Sie die Protokolle. Wenn Tomcat abstürzt, wird im Bin-Verzeichnis von Tomcat eine Protokolldatei mit der Bezeichnung „hs_err“ generiert. Öffnen Sie die neueste Protokolldatei. Als Erstes sehen Sie den folgenden Absatz:

# Es ist nicht genügend Speicher vorhanden, um die Java Runtime Environment fortzusetzen.
# Die native Speicherzuweisung (malloc) konnte 32756 Bytes für ChunkPool::allocate nicht zuweisen.
# Mögliche Gründe:
# Das System verfügt nicht über genügend physischen RAM oder Swap-Speicher
# Im 32-Bit-Modus wurde die Prozessgrößenbeschränkung erreicht
# Mögliche Lösungen:
# Reduzieren Sie die Speicherlast des Systems
# Erhöhen Sie den physischen Speicher oder den Swap-Speicher
# Überprüfen Sie, ob der Swap-Backing-Store voll ist
# Verwenden Sie 64-Bit-Java auf einem 64-Bit-Betriebssystem
# Java-Heapgröße verringern (-Xmx/-Xms)
# Anzahl der Java-Threads verringern
# Java-Thread-Stack-Größen verringern (-Xss)
# Größeren Code-Cache mit -XX:ReservedCodeCacheSize= einstellen
# Diese Ausgabedatei ist möglicherweise abgeschnitten oder unvollständig.
#
# Nicht genügend Arbeitsspeicherfehler (allocation.cpp:211), pid=7864, tid=6556
#
# JRE-Version: Java(TM) SE Runtime Environment (7.0_79-b15) (Build 1.7.0_79-b15)
# Java VM: Java HotSpot(TM) Server VM (24.79-b02, gemischter Modus, Windows-x86)
# Schreiben des Core Dumps fehlgeschlagen.

Dies bedeutet wahrscheinlich, dass nicht genügend Speicher vorhanden ist, um 32756 Byte Speicherplatz zuzuweisen. Hier sind einige Lösungen:

1. Reduzieren Sie die Systemspeicherlast.

2. Erhöhen Sie den physischen Speicher oder den Swap-Speicher.

3. Verwenden Sie 64-Bit-JDK auf einem 64-Bit-Betriebssystem;

4. Reduzieren Sie die Java-Heap-Größe;

5. Reduzieren Sie die Anzahl der Java-Threads.

6. Reduzieren Sie die Größe des Java-Thread-Stacks.

Aus dem obigen Inhalt können wir schließen, dass die JVM nicht 32756 Byte Speicherplatz zuweisen kann.

Von dem Moment an, als ich die Aufgabe erhielt, dachte ich immer, dass es sich um einen JVM-Konfigurationsfehler handelte, der zu unzureichendem Speicher führte, und ich nur die Konfiguration der neuen und alten Generation anpassen musste.

Sehen Sie sich weiterhin die Protokolldatei an und suchen Sie die Zeile „GC Heap History (10 events):“, die die Änderungen im Heap während der letzten 10 Garbage Collections der JVM aufzeichnet.

GC Heap-Verlauf (10 Ereignisse):
Ereignis: 572312.299 GC-Heap vorher
{Heap vor GC-Aufrufen=5046 (vollständig 357):
PSYoungGen gesamt 201472K, genutzt 200685K [0x573c0000, 0x63bc0000, 0x63bc0000)
Eden Space 198144K, 100 % genutzt [0x573c0000,0x63540000,0x63540000)
vom Speicherplatz 3328K, 76% genutzt [0x63540000,0x637bb528,0x63880000)
auf Speicherplatz 3328K, 0% genutzt [0x63880000,0x63880000,0x63bc0000)
ParOldGen gesamt 843776K, genutzt 422602K [0x23bc0000, 0x573c0000, 0x573c0000)
Objektspeicherplatz 843776K, 50% genutzt [0x23bc0000,0x3d872b18,0x573c0000)
PSPermGen gesamt 262144K, genutzt 51848K [0x03bc0000, 0x13bc0000, 0x23bc0000)
Objektspeicherplatz 262144K, 19% genutzt [0x03bc0000,0x06e62138,0x13bc0000)
Ereignis: 572312.305 GC-Heap nach
Heap nach GC-Aufrufen = 5046 (vollständig 357):
PSYoungGen gesamt 201472K, genutzt 1103K [0x573c0000, 0x63bc0000, 0x63bc0000)
Eden Space 198144K, 0 % genutzt [0x573c0000,0x573c0000,0x63540000)
vom Speicherplatz 3328K, 33% verwendet [0x63880000,0x63993c90,0x63bc0000)
auf Speicherplatz 3328K, 0% genutzt [0x63540000,0x63540000,0x63880000)
ParOldGen gesamt 843776K, genutzt 423618K [0x23bc0000, 0x573c0000, 0x573c0000)
Objektspeicherplatz 843776K, 50% genutzt [0x23bc0000,0x3d970b18,0x573c0000)
PSPermGen gesamt 262144K, genutzt 51848K [0x03bc0000, 0x13bc0000, 0x23bc0000)
Objektspeicherplatz 262144K, 19% genutzt [0x03bc0000,0x06e62138,0x13bc0000)
}
Ereignis: 572351.132 GC-Heap vorher
{Heap vor GC-Aufrufen=5047 (vollständig 357):
PSYoungGen gesamt 201472K, genutzt 199247K [0x573c0000, 0x63bc0000, 0x63bc0000)
Eden Space 198144K, 100 % genutzt [0x573c0000,0x63540000,0x63540000)
vom Speicherplatz 3328K, 33% verwendet [0x63880000,0x63993c90,0x63bc0000)
auf Speicherplatz 3328K, 0% genutzt [0x63540000,0x63540000,0x63880000)
ParOldGen gesamt 843776K, genutzt 423618K [0x23bc0000, 0x573c0000, 0x573c0000)
Objektspeicherplatz 843776K, 50% genutzt [0x23bc0000,0x3d970b18,0x573c0000)
PSPermGen gesamt 262144K, genutzt 51848K [0x03bc0000, 0x13bc0000, 0x23bc0000)
Objektspeicherplatz 262144K, 19% genutzt [0x03bc0000,0x06e62138,0x13bc0000)
Ereignis: 572351.137 GC-Heap nach
Heap nach GC-Aufrufen = 5047 (vollständig 357):
PSYoungGen gesamt 201472K, genutzt 1615K [0x573c0000, 0x63bc0000, 0x63bc0000)
Eden Space 198144K, 0 % genutzt [0x573c0000,0x573c0000,0x63540000)
vom Speicherplatz 3328K, 48% verwendet [0x63540000,0x636d3ec8,0x63880000)
auf Speicherplatz 3328K, 0% genutzt [0x63880000,0x63880000,0x63bc0000)
ParOldGen gesamt 843776K, genutzt 423674K [0x23bc0000, 0x573c0000, 0x573c0000)
Objektspeicherplatz 843776K, 50% genutzt [0x23bc0000,0x3d97eb18,0x573c0000)
PSPermGen gesamt 262144K, genutzt 51848K [0x03bc0000, 0x13bc0000, 0x23bc0000)
Objektspeicherplatz 262144K, 19% genutzt [0x03bc0000,0x06e62138,0x13bc0000)
}
Ereignis: 572398.649 GC-Heap vorher
{Heap vor GC-Aufrufen=5048 (vollständig 357):
PSYoungGen gesamt 201472K, genutzt 199759K [0x573c0000, 0x63bc0000, 0x63bc0000)
Eden Space 198144K, 100 % genutzt [0x573c0000,0x63540000,0x63540000)
vom Speicherplatz 3328K, 48% verwendet [0x63540000,0x636d3ec8,0x63880000)
auf Speicherplatz 3328K, 0% genutzt [0x63880000,0x63880000,0x63bc0000)
ParOldGen gesamt 843776K, genutzt 423674K [0x23bc0000, 0x573c0000, 0x573c0000)
Objektspeicherplatz 843776K, 50% genutzt [0x23bc0000,0x3d97eb18,0x573c0000)
PSPermGen gesamt 262144K, genutzt 51848K [0x03bc0000, 0x13bc0000, 0x23bc0000)
Objektspeicherplatz 262144K, 19% genutzt [0x03bc0000,0x06e62138,0x13bc0000)
Ereignis: 572398.655 GC-Heap nach
Heap nach GC-Aufrufen = 5048 (vollständig 357):
PSYoungGen gesamt 201472K, genutzt 1998K [0x573c0000, 0x63bc0000, 0x63bc0000)
Eden Space 198144K, 0 % genutzt [0x573c0000,0x573c0000,0x63540000)
vom Speicherplatz 3328K, 60% verwendet [0x63880000,0x63a73830,0x63bc0000)
auf Speicherplatz 3328K, 0% genutzt [0x63540000,0x63540000,0x63880000)
ParOldGen gesamt 843776K, genutzt 423703K [0x23bc0000, 0x573c0000, 0x573c0000)
Objektspeicherplatz 843776K, 50% genutzt [0x23bc0000,0x3d985cc0,0x573c0000)
PSPermGen gesamt 262144K, genutzt 51848K [0x03bc0000, 0x13bc0000, 0x23bc0000)
Objektspeicherplatz 262144K, 19% genutzt [0x03bc0000,0x06e62138,0x13bc0000)
}
Ereignis: 576881.689 GC-Heap vorher
{Heap vor GC-Aufrufen=5049 (vollständig 357):
PSYoungGen gesamt 201472K, genutzt 200142K [0x573c0000, 0x63bc0000, 0x63bc0000)
Eden Space 198144K, 100 % genutzt [0x573c0000,0x63540000,0x63540000)
vom Speicherplatz 3328K, 60% verwendet [0x63880000,0x63a73830,0x63bc0000)
auf Speicherplatz 3328K, 0% genutzt [0x63540000,0x63540000,0x63880000)
ParOldGen gesamt 843776K, genutzt 423703K [0x23bc0000, 0x573c0000, 0x573c0000)
Objektspeicherplatz 843776K, 50% genutzt [0x23bc0000,0x3d985cc0,0x573c0000)
PSPermGen gesamt 262144K, genutzt 51850K [0x03bc0000, 0x13bc0000, 0x23bc0000)
Objektspeicherplatz 262144K, 19% genutzt [0x03bc0000,0x06e62850,0x13bc0000)
Ereignis: 576881.696 GC-Heap nach
Heap nach GC-Aufrufen = 5049 (vollständig 357):
PSYoungGen gesamt 201472K, genutzt 3155K [0x573c0000, 0x63bc0000, 0x63bc0000)
Eden Space 198144K, 0 % genutzt [0x573c0000,0x573c0000,0x63540000)
aus Speicherplatz 3328K, 94% verwendet [0x63540000,0x63854cb0,0x63880000)
auf Speicherplatz 3328K, 0% genutzt [0x63880000,0x63880000,0x63bc0000)
ParOldGen gesamt 843776K, genutzt 423703K [0x23bc0000, 0x573c0000, 0x573c0000)
Objektspeicherplatz 843776K, 50% genutzt [0x23bc0000,0x3d985cc0,0x573c0000)
PSPermGen gesamt 262144K, genutzt 51850K [0x03bc0000, 0x13bc0000, 0x23bc0000)
Objektspeicherplatz 262144K, 19% genutzt [0x03bc0000,0x06e62850,0x13bc0000)
}
Ereignis: 580535.452 GC-Heap vorher
{Heap vor GC-Aufrufen=5050 (vollständig 357):
PSYoungGen gesamt 201472K, genutzt 201299K [0x573c0000, 0x63bc0000, 0x63bc0000)
Eden Space 198144K, 100 % genutzt [0x573c0000,0x63540000,0x63540000)
aus Speicherplatz 3328K, 94% verwendet [0x63540000,0x63854cb0,0x63880000)
auf Speicherplatz 3328K, 0% genutzt [0x63880000,0x63880000,0x63bc0000)
ParOldGen gesamt 843776K, genutzt 423703K [0x23bc0000, 0x573c0000, 0x573c0000)
Objektspeicherplatz 843776K, 50% genutzt [0x23bc0000,0x3d985cc0,0x573c0000)
PSPermGen gesamt 262144K, genutzt 51856K [0x03bc0000, 0x13bc0000, 0x23bc0000)
Objektspeicherplatz 262144K, 19% genutzt [0x03bc0000,0x06e64228,0x13bc0000)
Ereignis: 580535.459 GC-Heap nach
Heap nach GC-Aufrufen = 5050 (vollständig 357):
PSYoungGen gesamt 200960K, genutzt 1858K [0x573c0000, 0x63bc0000, 0x63bc0000)
Eden Space 197632K, 0 % genutzt [0x573c0000,0x573c0000,0x634c0000)
vom Speicherplatz 3328K, 55% verwendet [0x63880000,0x63a50be0,0x63bc0000)
auf Speicherplatz 3584K, 0% genutzt [0x634c0000,0x634c0000,0x63840000)
ParOldGen gesamt 843776K, genutzt 423703K [0x23bc0000, 0x573c0000, 0x573c0000)
Objektspeicherplatz 843776K, 50% genutzt [0x23bc0000,0x3d985cc0,0x573c0000)
PSPermGen gesamt 262144K, genutzt 51856K [0x03bc0000, 0x13bc0000, 0x23bc0000)
Objektspeicherplatz 262144K, 19% genutzt [0x03bc0000,0x06e64228,0x13bc0000)
}

Nachdem ich den obigen Inhalt gelesen hatte, konnte ich nicht feststellen, dass der Tomcat-Flash-Absturz durch unzureichenden Speicherplatz in der alten, permanenten und neuen Generation verursacht wurde. Es gab mehrere vollständige GCs, die durch eine 100-prozentige Auslastung des Eden-Speicherplatzes verursacht wurden, nach der Speicherbereinigung kehrte der Speicherplatz im Eden-Bereich jedoch auf das normale Niveau zurück.

Das Protokoll zeichnet auch die Heap-Nutzung auf, wenn Tomcat abstürzt:

Haufen
PSYoungGen gesamt 200960K, genutzt 95671K [0x573c0000, 0x63bc0000, 0x63bc0000)
Eden Space 197632K, 47 % genutzt [0x573c0000,0x5cf5d230,0x634c0000)
vom Speicherplatz 3328K, 55% verwendet [0x63880000,0x63a50be0,0x63bc0000)
auf Speicherplatz 3584K, 0% genutzt [0x634c0000,0x634c0000,0x63840000)
ParOldGen gesamt 843776K, genutzt 423703K [0x23bc0000, 0x573c0000, 0x573c0000)
Objektspeicherplatz 843776K, 50% genutzt [0x23bc0000,0x3d985cc0,0x573c0000)
PSPermGen gesamt 262144K, genutzt 51856K [0x03bc0000, 0x13bc0000, 0x23bc0000)
Objektspeicherplatz 262144K, 19% genutzt [0x03bc0000,0x06e64228,0x13bc0000)

Alles war so normal und doch gleichzeitig so seltsam.

Ich habe die vorherigen Protokolle durchgesehen und der Inhalt war ähnlich.

Ich habe die Protokolle ein paar Mal erneut gelesen und mich dieses Mal auf die in den Protokollen vorgeschlagenen Lösungen konzentriert:

# Reduzieren Sie die Speicherlast des Systems
# Erhöhen Sie den physischen Speicher oder den Swap-Speicher
# Überprüfen Sie, ob der Swap-Backing-Store voll ist
# Verwenden Sie 64-Bit-Java auf einem 64-Bit-Betriebssystem
# Java-Heapgröße verringern (-Xmx/-Xms)
# Anzahl der Java-Threads verringern
# Java-Thread-Stack-Größen verringern (-Xss)

Die folgenden Lösungen werden nicht übernommen:

  • Reduzieren Sie die Speicherlast des Systems. Der Systemspeicher ist ausreichend. Es sind 32 GB Speicher vorhanden, 20 GB bleiben ungenutzt. Eine Reduzierung des Speichers ist nicht erforderlich.
  • Erhöhen Sie den physischen Speicher oder den Swap-Speicher. Der Systemspeicher ist ausreichend. Es sind 32 GB Speicher vorhanden, 20 GB bleiben ungenutzt. Es besteht keine Notwendigkeit, den physischen Speicher zu erhöhen.
  • Verwenden Sie 64-Bit-Java auf einem 64-Bit-Betriebssystem. 32-Bit-Betriebssystem, 64-Bit-JDK kann nicht verwendet werden.

Es bleiben nur folgende drei Lösungen übrig:

  • Verringern Sie die Java-Heap-Größe (-Xmx/-Xms). Wenn der Heap zu groß eingestellt ist, wirkt sich dies auf den verbleibenden Speicher aus.
  • Anzahl der Java-Threads verringern
  • Verringern Sie die Größe des Java-Thread-Stapels (-Xss).

Um die Anzahl der Java-Threads zu reduzieren, müsste der Code geändert werden, was ebenfalls nicht praktikabel ist.

Schließlich nur

  • Java-Heap-Größe verringern (-Xmx/-Xms)
  • Verringern Sie die Größe des Java-Thread-Stapels (-Xss).

Dies sind die beiden Lösungen. Fangen Sie hier an, dann wird es Licht geben.

Schauen Sie sich zunächst die Lösung zur Reduzierung der Java-Thread-Stack-Größen (-Xss) an.

Java-Threads benötigen zum Ausführen ebenfalls Speicherplatz. Der Parameter -Xss gibt die Größe jedes Thread-Stapels und die Speichergröße an, die jedem von der JVM gestarteten Thread zugewiesen wird. In JDK 1.4 sind es 256 K und in JDK 1.5 und höher 1 M.

Die Parameter der Tomcat-JVM werden wie folgt eingestellt:

JAVA_OPTS=%JAVA_OPTS% -server -Xms1024m -Xmx1024m -Xmn200M -XX:PermSize=256M -XX:MaxPermSize=512m -XX:SurvivorRatio=1 -Xss256k

Die Stapelgröße jedes Java-Threads wurde über -Xss auf 256 KB eingestellt.

Wenn Sie in der Java-Sprache einen Thread erstellen, erstellt die virtuelle Maschine ein Thread-Objekt im JVM-Speicher und erstellt gleichzeitig einen Betriebssystem-Thread. Der Speicher dieses System-Threads ist nicht JVMMemory, sondern der verbleibende Speicher im System (MaxProcessMemory - JVMMemory - ReservedOsMemory).

Wenn ein Thread erstellt werden muss und der verbleibende Speicher des Betriebssystems nicht ausreicht, um ihn einem Java-Thread zuzuweisen, wird ein „Out of Memory“-Fehler gemeldet.

Da die Java-Thread-Stack-Größe über -Xss auf 256 KB eingestellt wurde, wurde entschieden, diese Lösung nicht zu verwenden.

Jetzt besteht die einzige verbleibende Lösung darin, die Java-Heap-Größe zu verringern (-Xmx/-Xms). Durch die Reduzierung der Heap-Größe bleibt genügend Speicherplatz für den Java-Thread-Stack übrig.

Das 32-Bit-Windows-Betriebssystem weist jedem Prozess 2 GB Speicherplatz zu, abzüglich der maximalen Kapazität des Heaps und der maximalen Kapazität von PermSize. Die verbleibende Kapazität ist für den Java-Thread-Stapel reserviert.

Nach der Analyse des Codes und vorheriger Fehlerprotokolle wurde festgestellt, dass der Fehler „Nicht genügend Arbeitsspeicher“ normalerweise bei etwa 350 Threads auftritt.
Zum Zeitpunkt des Fehlers waren weniger als 40 % des Heap-Speicherplatzes genutzt. Daher wurde beschlossen, den Java-Heap von 1 GB auf 768 M zu reduzieren.

Die geänderten JVM-Parameter sind wie folgt:

JAVA_OPTS=%JAVA_OPTS% -server -Xms768m -Xmx768m -Xmn200M -XX:PermSize=256M -XX:MaxPermSize=512m -XX:SurvivorRatio=1 -Xss256k

Bisher läuft das System seit einem Monat stabil und alle Parameteranzeigen liegen im normalen Bereich. Die maximale Heap-Auslastung beträgt lediglich 70 %.

Zusammenfassen:

1. Nachdem ich den Fehler dieses Mal behoben hatte, vertiefte ich mein Verständnis der Java-virtuellen Maschine, insbesondere der Konzepte Thread-Stack, Speicherheap, persistente Generierung, neue Generation usw.

2. Lesen Sie die Protokolldateien sorgfältig durch und schließen Sie mögliche Lösungen Schritt für Schritt aus. Berücksichtigen Sie die Betriebsumgebung des Gesamtsystems und finden Sie eine sinnvolle Lösung.

Das ist alles für diesen Artikel. Ich hoffe, dass der Inhalt dieses Artikels für Ihr Studium oder Ihre Arbeit von gewissem Referenzwert ist. Vielen Dank für Ihre Unterstützung von 123WORDPRESS.COM.

Das könnte Sie auch interessieren:
  • So steuern Sie den Start und das Herunterfahren von Tomcat in Asp.net
  • Beheben Sie das Problem, dass beim Herunterfahren von Tomcat mit shutdown.bat auch andere Tomcats heruntergefahren werden.
  • So starten/stoppen Sie den Tomcat-Server in Java
  • Java-Code schließt das Tomcat-Programm und analysiert die Probleme

<<:  Detaillierte Erläuterung des Fehlerproblems der Case-When-Anweisung

>>:  Detaillierte Erklärung der Funktionsklassifizierung und Beispiele für diese Zeigerfunktion in Javascript

Artikel empfehlen

Detaillierte Erklärung zur Verwendung des Arguments-Objekts in JavaScript

Inhaltsverzeichnis Vorwort Grundlegende Konzepte ...

Einfache Implementierung von Mini-Vue-Rendering

Inhaltsverzeichnis Vorwort Ziel Erster Schritt: S...

Bringen Sie Ihnen kostenlos bei, wie Sie AWS-Serverressourcen nutzen

AWS – Amazons Cloud-Computing-Serviceplattform Ic...

Einführung in die Installationsmethode in Vue

Inhaltsverzeichnis 1. Weltweit registrierte Kompo...

js zur Realisierung von Login- und Registrierungsfunktionen

In diesem Artikelbeispiel wird der spezifische Co...

Zusammenfassung der wichtigsten Docker-Befehle für Entwickler

Inhaltsverzeichnis Einführung in Docker Installat...

Das Erlebnis gestalten: Was auf dem Knopf liegt

<br />Vor Kurzem hat UCDChina eine Artikelse...

Methoden und Schritte für den Zugriff auf die Baidu Maps API mit JavaScript

Inhaltsverzeichnis 1. Baidu Map API-Zugriff 2. Ve...

Schritte zum Kapseln der Karussellkomponente in vue3.0

Inhaltsverzeichnis 1: Kapselungsidee 2. Verpackun...

Die ultimative Lösung zum Schreiben von Bash-Skripten mit Node.js

Inhaltsverzeichnis Vorwort zx-Bibliothek $`Befehl...

Schritte zur Methode „Mysql-Abfragedatenbankkapazität“

Abfrage der Gesamtgröße aller Datenbanken So geht...