Unterschiedlicher Speicherverbrauch bei ähnlichen Konfigurationen

Unterschiedlicher Speicherverbrauch bei ähnlichen Konfigurationen

Ich habe zwei verschiedene Tomcat 7-Instanzen auf zwei verschiedenen Servern (Oracle JDK7) mit nahezu gleicher Hardwarekonfiguration (beide > 24 GB RAM). Beide Tomcat-Server haben die gleiche Konfiguration und auf diesen Servern werden die gleichen Webanwendungen bereitgestellt. Die Catalina-Optionen sind die folgenden:

-XX:PermSize=128m -XX:MaxPermSize=512M -Xmx2048m -XX:+CMSIncrementalMode -XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC

Während eines Belastungstests (Belastung einer REST-API durch umfangreiche parallel ausgeführte Anfragen) kommt es bei einem der Server zu Problemen java.lang.OutOfMemoryError: Java heap space(hier ist der Stacktrace:http://pastebin.com/wuS1MVCC), der andere Server funktioniert einwandfrei. Ich habe keine Ahnung, warum das passiert. Hatte jemand schon einmal ein ähnliches Problem?

Antwort1

Was also passiert, ist, dass eine Ihrer Tomcat-JVMs versucht, den von Ihnen zugewiesenen Heap von 2048 MB zu überschreiten.

Es hört sich so an, als ob Sie sowohl nach einer konkreten Antwort als auch nach einer Checkliste mit Dingen suchen, die Sie ausprobieren können. Also los geht’s:

Wenn der Heap leer ist, liegt das entweder an einem Speicherleck, bei dem bei jeder Anforderung ein wenig Speicher verloren geht, oder in einem Lastszenario daran, dass Sie der JVM einfach mehr zumuten, als sie verarbeiten kann. Sie möchten herausfinden, welches davon das Problem ist. Sehen Sie sich also zunächst an, wie Sie Ihre Last erzeugen.

Wenn das Problem nur bei einer hohen Anzahl paralleler Anfragen auftritt, aber nie bei einer niedrigeren Anzahl, dann liegt das Problem darin, dass die Anzahl der Anfragen multipliziert mit dem zur Verarbeitung jeder Anfrage erforderlichen Speicher zu groß ist. Sie müssen entweder dafür sorgen, dass jede Anfrage weniger Speicher verwendet, oder die Parallelität irgendwie begrenzen.

Wenn das Problem nach der Verarbeitung einer bestimmten Anzahl von Anfragen unabhängig von der Parallelität auftritt, liegt ein Speicherverlust vor. Sie müssen ihn finden und den Speicher zurückfordern.

In beiden Fällen ist ein guter Heap-Speicheranalysator eine große Hilfe. Es gibt gute kommerzielle Tools wie YourKit Java Profiler oder kostenlose wie Eclipse Memory Analyzer. Suchen Sie sich ein Tool, das für Sie geeignet ist, und lernen Sie, wie Sie damit feststellen, was Speicher belegt. Beachten Sie, dass Sie das Tool nicht unbedingt zum Starten Ihres Programms verwenden müssen. Wenn Sie einen Belastungstest auf einem Server ausführen, können Sie mit dem Befehlszeilentool jmap aus dem JDK einen Heap-Dump in einer Datei erfassen und dann mit Ihrem Tool die Dump-Datei analysieren. Das Tool zeigt Ihnen, welche Objekte in Ihrem Heap Speicherplatz beanspruchen.

Antwort2

Es gibtetwaszwischen den beiden Systemen unterschiedlich, sonst wäre das Verhalten nicht anders. Beachten Sie, dass zu viel Zeit in der GC für zu wenig Ergebnis ebenfalls den Fehler verursachen kann. Wenn die GC nahe an den Grenzen des Heaps läuft, tritt diese Art von Problem bei der GC auf.

Übermäßige GC-Zeit und OutOfMemoryError

Der gleichzeitige Collector gibt einen OutOfMemoryError aus, wenn zu viel Zeit mit der Garbage Collection verbracht wird: Wenn mehr als 98 % der Gesamtzeit mit der Garbage Collection verbracht werden und weniger als 2 % des Heaps wiederhergestellt werden, wird ein OutOfMemoryError ausgegeben. Diese Funktion soll verhindern, dass Anwendungen über einen längeren Zeitraum ausgeführt werden und dabei nur geringe oder keine Fortschritte erzielen, weil der Heap zu klein ist. Bei Bedarf kann diese Funktion deaktiviert werden, indem der Befehlszeile die Option -XX:-UseGCOverheadLimit hinzugefügt wird.

verwandte Informationen