Der Java-Prozessspeicher ist viel größer als die angegebenen Grenzwerte

8

Ich habe die meisten verfügbaren Methoden erforscht, um herauszufinden, wie viel Speicher ein Java-Prozess wirklich nutzt. Bisher kann ich sagen, dass ich weiß, dass der gesamte zugewiesene Speicher eines oder mehrere der folgenden sein kann:

  • Heap Memory (angeblich von meinem -XX gesteuert: MaxHeapSize = 4096m)
  • Permanent Memory (angeblich von meinem -XX gesteuert: MaxPermSize = 1024m)
  • Reservierter Code-Cache (angeblich von meinem -XX gesteuert: ReservedCodeCacheSize = 256m)
  • N der Threads * Thread Size (angeblich von meiner -XX gesteuert: ThreadStackSize = 1024)

Aber die Ergebnisse sind zu verschieden von dem, was Linux mir sagt, mit einer der Methoden, die ich gefunden habe, um den Speicherverbrauch eines Java-Prozesses zu erhalten.

In meinem Fall ist es eine Tomcat-Instanz, die auf einem Ubuntu 11.10 x86_64-Rechner läuft, JVM 1.6_u26 64-bit, und ps -ALcf | grep org.apache.catalina.startup.Bootstrap | wc -l sagt mir, dass 145 Threads oder Prozesse laufen, die alle mit demselben Root-Prozess (Tomcat) verbunden sind .

Das alles zusammen sollte mir die maximale Speicherkapazität geben (4096MB) + (1024MB) + (256MB) + 145 * (1024KB) = 5521MB. Was jmap -heap PID sagt mir, was ManagementFactory.memoryMXBean.(heapMemoryUsage + nonHeapMemoryUsage).getCommitted() sagt mir, und der theoretische Wert oben sind alle auf Paar.

Nun zu der Linux-Seite, top und nmon beide sagt mir ResidentMemory von diesem Prozess zugeordnet ist 5,8GB - & gt; ungefähr 5939,2 MB. Aber ich weiß auch, das ist nur ein Teil des Speichers, der Teil im RAM-Speicher. VIRT by top und Size by nmon (beide sollen dasselbe darstellen) sagt mir, dass der Prozess 7530MB (oder genau 7710952KB by nmon ) ist. Dies ist TOO, das sich vom erwarteten Maximum unterscheidet: 2009MB über dem Maximum und laut jmap und jstat hat die Heap-Speicherzuweisung nicht einmal ihren Höchstwert erreicht (2048-OldSpace + 1534-Eden _ + _ Survivors).

top sagt mir auch Code Stack ist 36KB (fair, für den ersten Catalina-Starter), und Datenstack ist 7.3GB (den Rest darstellt).

Diese Tomcat-Server-Instanz ist die einzige Instanz, die auf dieser Maschine ausgeführt wird und eine gewisse Instabilität aufweist. Muss etwa alle drei Tage neu gestartet werden, da der Computer 7647544k RAM zur Verfügung hat und kein Swap (aus Performance-Gründen). Ich rechnete für die Grenzen, und ich erwartete, dass der Prozess ihnen folgte. Ich sah, dass es eine ziemlich gute Sicherheitsmarge war für alle anderen Dienste, die auf der Maschine laufen (keine davon sollte ssh und sich selbst stören): 7468 - 5521 = 1947. Das ist fast zu viel für eine "Sicherheitsmarge".

Ich möchte also verstehen, woher all diese Speicher verwendet werden und warum nicht die Grenze beachtet wurde. Wenn irgendwelche Informationen fehlen, werde ich gerne zur Verfügung stellen.

    
fredgalvao 30.05.2012, 14:29
quelle

2 Antworten

5

Einfach ausgedrückt: Die JVM verwendet mehr Speicher als in -Xms und -Xmx und den anderen Befehlszeilenparametern.

Hier ist ein sehr ausführlicher Artikel darüber, wie die JVM Speicher zuordnet und verwaltet Es ist nicht so einfach wie das, was Sie aufgrund Ihrer Annahmen in Ihrer Frage erwarten, es ist eine umfassende Lektüre wert.

Die ThreadStack-Größe in vielen Implementierungen hat Mindestgrenzen, die je nach Betriebssystem und manchmal JVM-Version variieren. Die Threadstack-Einstellung wird ignoriert, wenn Sie das Limit unterhalb des nativen Betriebssystemlimits für die JVM oder das Betriebssystem setzen (ulimit on * nix muss stattdessen manchmal gesetzt werden). Andere Befehlszeilenoptionen funktionieren auf die gleiche Weise und werden standardmäßig auf höhere Werte zurückgesetzt, wenn zu kleine Werte angegeben werden. Gehen Sie nicht davon aus, dass alle übergebenen Werte das darstellen, was tatsächlich verwendet wird.

Die Classloader und Tomcat haben mehr als einen, verbrauchen viel Speicher, der nicht einfach dokumentiert werden kann. Das JIT verschlingt viel Speicher und tauscht Raum für Zeit, was die meiste Zeit ein gutes Geschäft ist.

Die von Ihnen zitierten Zahlen liegen ziemlich nahe bei dem, was ich erwarten würde.

    
Jarrod Roberson 30.05.2012, 15:11
quelle
3

Der virtuelle Speicher ist die Menge des verwendeten Adressraums, etwas, worüber ich mich nicht sehr sorgen würde, da Sie eine 64-Bit-Anwendung haben. Der resident ist die Menge an tatsächlich verwendetem Hauptspeicher.

Sie können zu Ihrer Liste hinzufügen

  • shared libraries einschließlich der JVM. ~ 0,5 G
  • direkter Speicher (0 bis 4G) Das Maximum entspricht standardmäßig dem Heap-Maximum.
  • Speicherkarten. Keine Begrenzung.

Sie können pmap verwenden, um anzuzeigen, wie viel Adressraum zu welchem ​​Zweck verwendet wird.

BTW: Ich habe Prozess, der 640G VIRT in top aufgrund von Speicherabbilddateien zeigt. Es kann viel höher sein als die Bewohnergröße. ;)

    
Peter Lawrey 30.05.2012 15:13
quelle

Tags und Links