Java Container-Anwendungs-Speicheranalyse

Für Containeranwendungen ist es schwierig, Probleme aufgrund von Speicherübernutzung aufzudecken. Wenn die Nutzung über den Speichergrenzwert des Containers hinausgeht, kann eine Anwendung stillschweigend versagen, ohne Spuren zu hinterlassen.

In diesem Artikel werde ich einige der Techniken durchgehen, die zur Identifizierung der Quelle der Speicherauslastung in einer Java-Containeranwendung verwendet werden können.

Speichertyp

In einem typischen Java-Anwendung, Speicher kann grob in Heap und Non-Heap unterteilt werden. Heap-Speicher kann durch Bereitstellen entsprechender JVM-Parameter beim Starten jeder Java-Anwendung festgelegt werden.

Non-Heap-Speicher besteht aus dem systemeigenen Speicher, der vom JVM-eigenen oder von einer innerhalb der Anwendung verwendeten Bibliothek über JNI (Java Native Interface) verwendet wird.

Methode

Für Heap-Speicher kann ein Heap-Dump erstellt und mithilfe von Heap-Dump-Analysewerkzeugen analysiert werden. Ein sehr gutes Werkzeug für die Analyse von Heap-Dumps ist das eclipse MAT.

Java bietet eine Möglichkeit, die Zuweisung von systemeigenem Speicher zu verfolgen, indem native memory tracking aktiviert wird, aber es kann nicht alle vom systemeigenen Bibliotheken zugewiesenen Speicher offenlegen.

Jemalloc ist ein Werkzeug, das zur Verfolgung von Speicher, der von systemnahen Bibliotheken zugewiesen wird, verwendet werden kann. Systemnaher Speicher wird mit einem Standard-Speicherzuweiser namens malloc zugewiesen. Jemalloc ist eine allgemeine malloc-Implementierung, bei der die Überwachung der Speicherzuweisung aktiviert werden kann. Es verfolgt alle systemnahen Speicherzuweisungen und generiert Heap-Profil-Dumps.

Diese Heap-Profile können dann mit dem Jeprof Werkzeug analysiert werden. Jeprof erstellt den Heap-Zuweisungsbericht und zeigt den Speicher an, der von Funktionen im Anwendungsprogramm verwendet wird.

Analyse

Im Folgenden finden Sie eine Speicheranalyse einer Beispiel-Container-Java-Anwendung. Die Anwendung lädt ein Beispiel Tensorflow Modell, um die Nutzung systemnahen Speichers zu ermöglichen, und läuft in einem Docker-Container.

Folgendes zeigt den Docker-Speicherverbrauch. Es beträgt 254MB. Versuchen wir, die Quelle des Speicherverbrauchs zu identifizieren.

Gesamtspeicher

Um einen Eindruck von der insgesamt von dem Anwendungsprozess verwendeten Speichermenge zu erhalten, können wir den Resident Set Size (RSS) überprüfen. Dies ist die insgesamt zugesicherte Speichermenge, die im Hauptspeicher oder RAM vorliegt. Es gibt mehrere Werkzeuge, die dabei helfen können, dies zu überprüfen, wie top, ps oder pmap.

Die Überprüfung von RSS hilft nicht, die Quelle des Ressourcenverbrauchs genau zu identifizieren. Für die Beispielanwendung beträgt der Gesamtrss mit dem unten stehenden Befehl 376MB.

Shell

 

ps --no-header -o rss $(pidof java)

Heap-Analyse

Unten ist der Heap-Speicherverbrauch dargestellt, wie er vom Eclipse MAT-Tool generiert wurde. Der insgesamt beibehaltene Heap beträgt 2,2MB, was weit unter dem Gesamtspeicherverbrauch liegt, wie er von Docker angezeigt wird, und zeigt an, dass der Großteil des Verbrauchs aus dem nicht-heap Bereich stammt.

Native-Speicheranalyse

Nach der Überprüfung des native Speicherzusammenfassung mit dem unten stehenden Befehl scheint der Gesamt-Speicherverbrauch ungefähr 99MB zu betragen. Dieser Wert ist jedoch geringer als der Gesamt-Speicherverbrauch und identifiziert die Hauptursache des Problems nicht genau.

Shell

 

jcmd $(pidof java) VM.native_memory \
    | grep -P "Total.*committed=" \
    | grep -o -P "(?<=committed=)[0-9]+(?=KB)"

Off-Heap-Speicheranalyse

Eine Analyse mithilfe von Jemalloc und Jeprof zeigt, dass der native Speicherverbrauch hauptsächlich auf die Tensorflow-Bibliothek zurückzuführen ist, mit einem Gesamtverbrauch von ungefähr 112MB.

Diese Erkenntnis gibt einen klaren Hinweis auf die Quelle des native Speicherverbrauchs und kann weiter untersucht werden, um übermäßigen Verbrauch zu minimieren.

Schlussfolgerung

Die Java-Speicheranalyse ist entscheidend, insbesondere für containerbasierte Anwendungen. Die Kenntnis der Speicherquellen in einer Anwendung kann dabei helfen, das Speicherbedürfnis zu verstehen und die Anwendungskosten durch den Verzicht auf unnötigen Verbrauch zu senken.

Bei der Überprüfung des Speicherverbrauchs müssen alle Arten von Speicher und ihre Quellen genau identifiziert werden. Heap-Dump-Analyse kann Quellen des Heap-Speicherverbrauchs identifizieren, und Jemalloc und Jeprof sind hilfreich, um Quellen des native Speicherverbrauchs zu identifizieren.

Beispielanwendungscode-Link

https://github.com/parveensaini/JavaContainerMemoryAnalysis

Source:
https://dzone.com/articles/java-container-application-memory-analysis