it-swarm.com.de

Wie kann ich die Speichernutzung von Java überwachen?

Wir haben eine j2ee-Anwendung, die auf Jboss ausgeführt wird, und wir möchten die Speichernutzung überwachen. Derzeit verwenden wir den folgenden Code

    System.gc();
    Runtime rt = Runtime.getRuntime();
    long usedMB = (rt.totalMemory() - rt.freeMemory()) / 1024 / 1024;
    logger.information(this, "memory usage" + usedMB);

Dieser Code funktioniert gut. Das heißt, es zeigt eine Gedächtniskurve, die der Realität entspricht. Wenn wir eine große XML-Datei aus einer Datenbank erstellen, steigt eine Kurve an und sinkt, nachdem die Extraktion abgeschlossen ist.

alt text

Ein Berater sagte uns, dass der explizite Aufruf von gc () falsch ist, "lass jvm entscheiden, wann gc ausgeführt werden soll". Im Grunde waren seine Argumente die gleichen wie hier diskutiert . Aber ich verstehe immer noch nicht:

  • wie kann ich meine Speichernutzungskurve haben?
  • was ist los mit dem expliziten gc ()? Ich interessiere mich nicht für kleine Leistungsprobleme, die mit expliziten gc () auftreten können und die ich in 1-3% schätzen würde. Was ich brauche, ist ein Speicher- und Thread-Monitor, der mir bei der Analyse unseres Systems beim Kunden hilft.
58
Oleg Pavliv

Wenn Sie wirklich sehen möchten, was im VM) - Speicher vor sich geht, sollten Sie ein gutes Tool wie VisualVM verwenden. Diese Software ist kostenlos und bietet eine großartige Möglichkeit dazu schau was los ist.

Bei expliziten gc () -Aufrufen ist nichts wirklich "falsch". Denken Sie jedoch daran, dass Sie beim Aufrufen von gc () "vorschlagen", dass der Garbage Collector ausgeführt wird. Es gibt keine Garantie dafür, dass es genau zu dem Zeitpunkt ausgeführt wird, zu dem Sie diesen Befehl ausführen.

51
amischiefr

Es gibt Tools, mit denen Sie die Speichernutzung der VM überwachen können. Die VM kann Speicherstatistiken mit JMX verfügbar machen . Sie können auch GC-Statistiken drucken , um zu sehen, wie sich der Speicher im Zeitverlauf verhält.

Das Aufrufen von System.gc () kann die Leistung des GC beeinträchtigen, da Objekte vorzeitig von den neuen zu den alten Generationen verschoben und schwache Referenzen vorzeitig gelöscht werden. Dies kann zu einer verringerten Speichereffizienz, längeren GC-Zeiten und verringerten Cache-Treffern führen (für Caches, die schwache Refs verwenden). Ich stimme Ihrem Berater zu: System.gc () ist schlecht. Ich würde so weit gehen, deaktivieren mit der Befehlszeilenoption.

Sie können einen Blick auf stagemonitor werfen. Es ist ein Open Source Java (Web-) Anwendungsleistungsmonitor. Es erfasst Antwortzeitmetriken, JVM-Metriken, Anforderungsdetails (einschließlich eines vom Anforderungsprofiler erfassten Aufrufstapels) und mehr sehr niedrig.

Optional können Sie die Datenbankgraphit der großen Zeitreihen verwenden, um eine lange Historie von Datenpunkten zu speichern, die Sie mit ausgefallenen Dashboards anzeigen können.

Beispiel: JVM Memory Dashboard

Schauen Sie sich die Projektwebsite an, um Screenshots, Funktionsbeschreibungen und Dokumentationen zu sehen.

Hinweis: Ich bin der Entwickler von stagemonitor

10
Felix

Ich würde sagen, dass der Berater in der Theorie Recht hat und Sie in der Praxis Recht haben. Wie das Sprichwort sagt :

Theorie und Praxis sind in der Theorie gleich. In der Praxis sind sie nicht.

Die Java spec besagt, dass System.gc den Aufruf der Garbage Collection vorschlägt. In der Praxis wird nur ein Thread erzeugt und sofort auf der Sun JVM ausgeführt.

Obwohl Sie theoretisch eine fein abgestimmte JVM-Implementierung der Garbage Collection durcheinander bringen könnten, sollten Sie sich keine Sorgen machen, es sei denn, Sie schreiben generischen Code, der auf einer beliebigen JVM bereitgestellt werden soll. Wenn es bei Ihnen funktioniert, tun Sie es.

9
Yishai
8
Tom

Informieren Sie sich über die Vorgänge in Tomcat mithilfe von Visual VM. http://www.skill-guru.com/blog/2010/10/05/increasing-permgen-size-in-your-server/ alt text

alt text

6
vsingh

Das explizite Ausführen von System.gc () auf einem Produktionssystem ist eine schreckliche Idee. Wenn der Speicher eine beliebige Größe erreicht, kann das gesamte System einfrieren, während ein vollständiger GC ausgeführt wird. Auf einem Server mit einer Größe von mehreren Gigabyte kann dies sehr auffällig sein, je nachdem, wie die JVM konfiguriert ist und wie viel Headroom sie hat usw. usw. - Ich habe Pausen von mehr als 30 Sekunden gesehen.

Ein weiteres Problem besteht darin, dass Sie durch einen expliziten Aufruf von GC nicht überwachen, wie die JVM die GC ausführt, sondern sie tatsächlich ändern. Je nachdem, wie Sie die JVM konfiguriert haben, wird die Garbage-Collection durchgeführt, wenn dies angemessen ist, und in der Regel schrittweise (Es wird nicht nur ein vollständiger GC ausgeführt, wenn der Speicher voll ist.) Das, was Sie ausdrucken, hat nichts mit dem zu tun, was die JVM alleine macht - zum einen werden Sie wahrscheinlich weniger automatische/inkrementelle GCs sehen, wenn Sie den Speicher manuell löschen.

Wie in Nick Holts Post hervorgehoben, gibt es bereits Optionen zum Drucken von GC-Aktivitäten als JVM-Flags.

Sie könnten einen Thread haben, der gerade kostenlos ausgedruckt wird und in angemessenen Abständen verfügbar ist. Dies zeigt Ihnen die tatsächliche Speichernutzung.

5
Steve B.

Schauen Sie sich die JVM-Argumente an: http://Java.Sun.com/javase/technologies/hotspot/vmoptions.jsp#DebuggingOptions

XX: -PrintGC Nachrichten bei der Garbage Collection drucken. Überschaubar.

-XX: -PrintGCDetails Gibt weitere Details bei der Garbage Collection aus. Überschaubar. (Eingeführt in 1.4.0.)

-XX: -PrintGCTimeStamps Gibt Zeitstempel bei der Garbage Collection aus. Verwaltbar (eingeführt in 1.4.0.)

-XX: -PrintTenuringDistribution Gibt Informationen zum Beschäftigungsalter aus.

Während Sie die JVM nicht durch explizite Aufrufe von System.gc() verärgern, haben sie möglicherweise nicht den erwarteten Effekt. Um wirklich zu verstehen, was mit dem Speicher in einer JVM los ist, lesen Sie alles, was Brian Goetz schreibt.

5
Nick Holt

Wenn Sie dies auf eine nette Art und Weise von der Kommandozeile aus tun möchten, verwenden Sie jstat:

http://Java.Sun.com/j2se/1.5.0/docs/tooldocs/share/jstat.html

Es liefert in konfigurierbaren Intervallen Rohdaten, die für Protokollierungs- und Grafikzwecke sehr nützlich sind.

4
Pablojim

Wenn Sie den von JMX bereitgestellten Verlauf von GC-Läufen verwenden, können Sie dieselben Vorher-/Nachher-Nummern verwenden. Sie müssen lediglich keine GC erzwingen.

Sie müssen nur bedenken, dass diese GC-Läufe (normalerweise einer für die alte und einer für die neue Generation) nicht in regelmäßigen Intervallen ausgeführt werden. Daher müssen Sie auch die Startzeit für das Plotten extrahieren (oder Sie plotten für die meisten gegen eine Sequenznummer) praktische Zwecke, die zum Zeichnen ausreichen würden).

Beispielsweise gibt es unter Oracle HotSpot VM mit ParNewGC eine JMX-MBean mit dem Namen Java.lang:type=GarbageCollector,name=PS Scavenge, es hat ein Attribut LastGCInfo, es gibt CompositeData des letzten YG-Scavenger-Laufs zurück. Es wird mit duration, absolut startTime und memoryUsageBefore und memoryUsageAfter aufgezeichnet.

Verwenden Sie einfach einen Timer, um dieses Attribut zu lesen. Immer wenn eine neue startTime angezeigt wird, wissen Sie, dass sie ein neues GC-Ereignis beschreibt, extrahieren Sie die Speicherinformationen und suchen weiter nach dem nächsten Update. (Ich bin mir nicht sicher, ob ein AttributeChangeNotification irgendwie verwendet werden kann.)

Tipp: In Ihrem Timer können Sie die Entfernung zum letzten GC-Lauf messen. Wenn dies für die Auflösung Ihres Plots zu lang ist, können Sie System.gc () unter bestimmten Bedingungen aufrufen. Aber ich würde das nicht in einer OLTP Instanz tun.

2
eckes

Wenn Sie Java 1.5) verwenden, können Sie sich ManagementFactory.getMemoryMXBean () ansehen, das Ihnen Zahlen für alle Arten von Speicher gibt. Heap und non-heap, perm-gen.

Ein gutes Beispiel kann dort gefunden werden http://www.freshblurbs.com/explaining-Java-lang-outofmemoryerror-permgen-space

2
Zoukaye

Wie bereits vorgeschlagen, versuchen Sie es mit VisualVM, um eine grundlegende Ansicht zu erhalten.

Sie können auch Eclipse MAT verwenden, um eine detailliertere Speicheranalyse durchzuführen.

Es ist in Ordnung, ein System.gc () zu machen, solange Sie nicht davon abhängig sind, um die Richtigkeit Ihres Programms zu gewährleisten.

0
Aakash

Das Problem mit system.gc ist, dass die JVM dem Garbage Collector basierend auf der Speichernutzung bereits automatisch Zeit zuweist.

Wenn Sie beispielsweise wie ein mobiles Gerät in einem sehr speicherbeschränkten Zustand arbeiten, können Sie mit System.gc manuell mehr Zeit für diese Garbage Collection reservieren, allerdings auf Kosten der CPU-Zeit (aber, wie Sie sagten) , du bist nicht so besorgt über Performance-Probleme von gc).

Die beste Vorgehensweise wäre wahrscheinlich nur dort zu verwenden, wo Sie möglicherweise große Mengen der Freigabe vornehmen (wie das Leeren eines großen Arrays).

Alles in allem sollten Sie, da Sie nur über die Speichernutzung besorgt sind, gc anrufen oder, noch besser, prüfen, ob dies in Ihrem Fall einen großen Unterschied im Speicher ausmacht, und dann entscheiden.

0
bgw