Wir versuchen, die Speichernutzung des Java-Prozesses unter moderater Last zu untersuchen.
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
12663 test 20 0 8378m 6.0g 4492 S 43 8.4 162:29.95 java
Wie Sie sehen können, haben wir einen residenten Speicher von 6 GB. Nun ist der interessante Teil der folgende: Der Prozess wird mit diesen Parametern ausgeführt:
- -Xmx2048m
- -Xms2048m
- -XX: NewSize = 512m
- -XX: MaxDirectMemorySize = 256 m
- ... einige andere für GC und so
Wenn wir uns diese Einstellungen und die tatsächliche Speichernutzung ansehen, sind wir erstaunt darüber, welchen Unterschied wir von diesem Prozess erwarten und was er tatsächlich verwendet.
Normalerweise werden unsere Speicherprobleme durch Analysieren des Heap-Dumps gelöst, aber in diesem Fall wird unser Speicher irgendwo außerhalb des Heaps verwendet.
Fragen: Was wären die Schritte, um den Grund für eine so hohe Speichernutzung zu finden? Welche Tools könnten uns dabei helfen, herauszufinden, wie viel Speicher in diesem Prozess verwendet wird?
EDIT 0
Es sieht nicht so aus, als wäre dies ein Heap-Problem, da wir dort noch ziemlich viel Platz haben:
jmap -heap 12663
Ergebnisse in (bearbeitet, um Platz zu sparen)
Heap Configuration:
MinHeapFreeRatio = 40
MaxHeapFreeRatio = 70
MaxHeapSize = 2147483648 (2048.0MB)
NewSize = 536870912 (512.0MB)
MaxNewSize = 536870912 (512.0MB)
OldSize = 1610612736 (1536.0MB)
NewRatio = 7
SurvivorRatio = 8
PermSize = 21757952 (20.75MB)
MaxPermSize = 85983232 (82.0MB)
New Generation: 45.7% used
Eden Space: 46.3% used
From Space: 41.4% used
To Space: 0.0% used
concurrent mark-sweep generation: 63.7% used
Perm Generation: 82.5% used
EDIT 1
Wenn wir die pmap benutzen, können wir sehen, dass es eine ganze Menge von Zuweisungen von 64 MB gibt:
pmap -x 12663 | grep rwx | sort -n -k3 | less
Ergebnisse in:
... a lot more of these 64Mb chunks
00007f32b8000000 0 65508 65508 rwx-- [ anon ] <- what are these?
00007f32ac000000 0 65512 65512 rwx-- [ anon ]
00007f3268000000 0 65516 65516 rwx-- [ anon ]
00007f3324000000 0 65516 65516 rwx-- [ anon ]
00007f32c0000000 0 65520 65520 rwx-- [ anon ]
00007f3314000000 0 65528 65528 rwx-- [ anon ]
00000000401cf000 0 241904 240980 rwx-- [ anon ] <- Direct memory ?
000000077ae00000 0 2139688 2139048 rwx-- [ anon ] <- Heap ?
Wie kann man also herausfinden, was diese 64-MB-Chunks sind? Was benutzt sie? Welche Art von Daten sind in ihnen?
Vielen Dank
Antworten:
Das Problem hängt möglicherweise mit diesem Problem zusammen .
Wenn Sie mehrere Threads haben, die Speicher zuweisen, vergrößert glibc die Anzahl der verfügbaren Arenen, aus denen die Zuweisung erfolgt, um Sperrenkonflikte zu vermeiden. Eine Arena ist 64 MB groß. Die Obergrenze ist das 8-fache der Anzahl der Kerne. Arenen werden nach Bedarf erstellt, wenn ein Thread auf eine Arena zugreift, die bereits gesperrt ist, sodass sie mit der Zeit wächst.
In Java, wo Sie mit Threads bestreuen, kann dies schnell dazu führen, dass viele Arenen erstellt werden. Und es gibt Zuteilungen, die über diese Arenen verteilt sind. Anfänglich wird jeder 64-MB-Arena nur nicht festgelegter Speicher zugeordnet, aber wenn Sie Zuordnungen vornehmen, beginnen Sie, den tatsächlichen Speicher für diese zu verwenden.
Auf Ihrer pmap sind wahrscheinlich ähnliche Einträge zu finden. Beachten Sie, wie 324 K + 65212 K = 65536 K, 560 K + 64976 K = 65536 K, 620 K + 64916 K = 65536 K. Das heißt, sie summieren sich auf 64 MB.
Wie für Abhilfen : Der Fehler erwähnen einige Umgebungsparameter Sie festlegen können , um die Anzahl der Arenen zu begrenzen, aber Sie müssen hoch genug , um eine glibc Version.
quelle
Wie wäre es mit Lamdba Probe ? Unter anderem kann es Ihnen Aufschlüsselungen der Speicherauslastung ähnlich dem folgenden Screenshot anzeigen:
Manchmal
pmap -x your_java_pid
kann das auch hilfreich sein.quelle
JProfiler könnte etwas sein, was Sie suchen, aber es ist nicht kostenlos. Ein weiteres gutes und kostenloses Tool zur Untersuchung der Speichernutzung von Java-Prozessen ist Java VisualVM, das als JDK-Tool in Oracle / Sun JDK-Distributionen verfügbar ist. Ich persönlich würde eine ganzheitlichere Herangehensweise an das Problem empfehlen (z. B. die Überwachung von JDK + OS + -Datenträgern usw.) - die Verwendung eines Netzwerküberwachungssystems - Nagios, Verax NMS oder OpenNMS.
quelle
Das Problem liegt außerhalb des Haufens, daher sind die besten Kandidaten:
Aufgrund der Tatsache, dass Sie die Größe des direkten Puffers begrenzt haben, ist meiner Meinung nach das JNI-Leck der beste Kandidat.
quelle
Es gibt ein praktisches Tool zum Anzeigen der Zuordnung des im JDK enthaltenen Heapspeichers, jmap genannt. Darüber hinaus gibt es einen Stapel usw. (Xss). Führen Sie diese beiden jmap-Befehle aus, um weitere Informationen zur Speichernutzung zu erhalten:
Um noch mehr Informationen zu erhalten, können Sie sich mit jconsole (ebenfalls im JDK enthalten) mit dem Prozess verbinden. Jconsole setzt jedoch voraus, dass JMX in der Anwendung konfiguriert wird.
quelle
Verwenden Sie JVisualVM. Es gibt verschiedene Ansichten, aus denen hervorgeht, wie viel Heap-Speicher verwendet wird, PermGen und so weiter und so fort.
Wie für die Beantwortung Ihrer Frage. Java handhabt den Speicher ganz anders als erwartet.
Wenn Sie die Parameter -Xms und -Xmx festlegen, teilen Sie der JVM mit, wie viel Speicher im Heap reserviert werden soll und wie viel maximal reserviert werden soll.
Wenn Sie eine Java-Anwendung haben, die insgesamt 1 MB Arbeitsspeicher verwendet, aber -Xms256m -Xmx2g übergeben hat, initialisiert sich die JVM mit 256 MB Arbeitsspeicher. Es wird nicht weniger als das verwenden. Es spielt keine Rolle, dass Ihre Anwendung nur 1 m Speicher benötigt.
Zweitens. In diesem Fall reserviert die JVM so viel Speicher, wie für die Bearbeitung der Anforderung erforderlich ist, wenn die App zu einem bestimmten Zeitpunkt mehr als 256 m Arbeitsspeicher verwendet. Die Größe des Heapspeichers wird jedoch nicht auf den Mindestwert zurückgesetzt. Zumindest nicht unter den meisten Umständen.
In Ihrem Fall weist die JVM zu Beginn 2 g zu und verwaltet diesen, da Sie den minimalen und maximalen Speicher auf 2 g festlegen.
Die Java-Speicherverwaltung ist recht komplex und das Optimieren der Speichernutzung kann eine Aufgabe für sich sein. Es gibt jedoch viele Ressourcen, die helfen können.
quelle