Come monitorare l'utilizzo della memoria Java?


Abbiamo un'applicazione j2ee in esecuzione su Jboss e vogliamo monitorare il suo utilizzo della memoria. Attualmente usiamo il seguente codice

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

Questo codice funziona bene. Ciò significa che mostra la curva di memoria che corrisponde alla realtà. Quando creiamo un grande file xml da un DB una curva sale, dopo che l'estrazione è terminata scende.

testo alt

Un consulente ci ha detto che chiamare gc() esplicitamente è sbagliato, "lascia che jvm decida quando eseguire gc". Fondamentalmente i suoi argomenti erano gli stessi come disscussed qui . Ma ancora non capisco:

  • come posso avere la mia curva di utilizzo della memoria?
  • cosa c'è di sbagliato nell'esplicito gc()? Non mi interessano i piccoli problemi di prestazioni che possono verificarsi con explicit gc () e che stimerei in 1-3%. Quello di cui ho bisogno è il monitor di memoria e thread che mi aiuta nell'analisi del nostro sistema sul sito del cliente.
Author: Community, 2009-06-29

14 answers

Se vuoi davvero guardare cosa sta succedendo nella memoria della VM dovresti usare un buon strumento come VisualVM. Questo software è gratuito ed è un ottimo modo per vedere cosa sta succedendo.

Nulla è veramente "sbagliato" con le chiamate esplicite di gc (). Tuttavia, ricorda che quando chiami gc () stai "suggerendo" che il garbage collector funzioni. Non vi è alcuna garanzia che verrà eseguito nel momento esatto in cui si esegue quel comando.

 48
Author: amischiefr, 2018-01-20 03:29:04

Esistono strumenti che consentono di monitorare l'utilizzo della memoria della VM. La VM può esporre le statistiche di memoria utilizzando JMX . Puoi anche stampare le statistiche GC per vedere come funziona la memoria nel tempo.

Sistema di richiamo.gc () può danneggiare le prestazioni del GC perché gli oggetti verranno spostati prematuramente dalle nuove alle vecchie generazioni e i riferimenti deboli verranno cancellati prematuramente. Ciò può comportare una diminuzione dell'efficienza della memoria, tempi di GC più lunghi e una diminuzione degli hit della cache (per cache che utilizzano riferimenti deboli). Sono d'accordo con il tuo consulente: Sistema.gc () è cattivo. Mi spingerei fino a disabilitarlo usando l'opzione della riga di comando.

 28
Author: Mr. Shiny and New 安宇, 2016-02-16 16:27:47

Direi che il consulente ha ragione nella teoria e tu hai ragione nella pratica. Come dice il proverbio :

In teoria, teoria e pratica sono uguali. In pratica, non lo sono.

La specifica Java dice che il sistema.gc suggerisce di chiamare garbage collection. In pratica, genera solo un thread e viene eseguito immediatamente sulla JVM Sun.

Anche se in teoria potresti rovinare un'implementazione JVM finemente sintonizzata della garbage collection, a meno che stai scrivendo codice generico destinato a essere distribuito su qualsiasi JVM là fuori, non preoccuparti. Se funziona per te, fallo.

 9
Author: Yishai, 2009-06-29 15:47:58

Puoi dare un'occhiata a stagemonitor. Si tratta di un open source java (web) monitor delle prestazioni delle applicazioni. Acquisisce metriche del tempo di risposta, metriche JVM, dettagli delle richieste (incluso uno stack di chiamate catturato dal profiler delle richieste) e altro ancora. Il sovraccarico è molto basso.

Opzionalmente, è possibile utilizzare il grande database graphite timeseries con esso per memorizzare una lunga storia di punti dati che è possibile guardare con cruscotti di fantasia.

Esempio: Dashboard di memoria JVM

Dai un'occhiata al sito web del progetto per vedere screenshot, descrizioni di funzionalità e documentazione.

Nota: sono lo sviluppatore di stagemonitor

 9
Author: Felix, 2014-07-30 15:01:50

Sbirciare in ciò che sta accadendo all'interno di tomcat attraverso Visual VM. http://www.skill-guru.com/blog/2010/10/05/increasing-permgen-size-in-your-server / testo alt

testo alt

 6
Author: vsingh, 2010-10-06 21:27:10

Dai un'occhiata agli argomenti della JVM: http://java.sun.com/javase/technologies/hotspot/vmoptions.jsp#DebuggingOptions

XX: - PRINTGC Stampa messaggi alla garbage collection. Gestibile.

- XX: - PrintGCDetails Stampa maggiori dettagli in garbage collection. Gestibile. (Introdotto in 1.4.0.)

- XX: - PrintGCTimeStamps Stampa timestamp alla garbage collection. Gestibile (introdotto in 1.4.0.)

- XX: - PrintTenuringDistribution Stampa informazioni sull'età di possesso.

Mentre non sconvolgerai la JVM con chiamate esplicite a System.gc() potrebbero non avere l'effetto che ti aspetti. Per capire davvero cosa sta succedendo con la memoria in una JVM con leggi qualsiasi cosa e tutto il Brian Goetz scrive.

 5
Author: Nick Holt, 2009-06-29 16:03:39

Sistema in esecuzione in modo esplicito.gc () su un sistema di produzione è una pessima idea. Se la memoria raggiunge qualsiasi dimensione, l'intero sistema può bloccarsi mentre è in esecuzione un GC completo. Su un server di dimensioni multi-gigabyte, questo può essere facilmente molto evidente, a seconda di come è configurata la jvm e di quanto spazio libero ha, ecc.

Un altro problema è che chiamando esplicitamente GC non stai effettivamente monitorando come la JVM sta eseguendo il GC, sei in realtà lo altera, a seconda di come hai configurato la JVM, si raccoglierà quando appropriato, e di solito in modo incrementale (non esegue solo un GC completo quando si esaurisce la memoria). Quello che stamperai non sarà niente come quello che la JVM farà da sola - per prima cosa probabilmente vedrai meno GC automatici / incrementali mentre cancellerai manualmente la memoria.

Come sottolinea il post di Nick Holt, le opzioni per stampare l'attività GC esistono già come JVM bandiera.

Potresti avere un thread che stampa solo gratuitamente e disponibile a intervalli ragionevoli, questo ti mostrerà l'effettivo utilizzo di mem.

 5
Author: Steve B., 2009-06-29 16:10:17

Se ti piace un bel modo per farlo dalla riga di comando usa jstat:

Http://java.sun.com/j2se/1.5.0/docs/tooldocs/share/jstat.html

Fornisce informazioni grezze a intervalli configurabili che è molto utile per scopi di registrazione e grafica.

 4
Author: Pablojim, 2009-06-29 20:01:25

Se si utilizza java 1.5, è possibile esaminare ManagementFactory.getMemoryMXBean () che ti danno numeri su tutti i tipi di memoria. heap e non-heap, perm-gen.

Un buon esempio può essere trovato lì http://www.freshblurbs.com/explaining-java-lang-outofmemoryerror-permgen-space

 2
Author: Zoukaye, 2009-06-29 15:57:29

Se si utilizza la cronologia fornita da JMX delle esecuzioni GC, è possibile utilizzare gli stessi numeri prima/dopo, non è necessario forzare un GC.

Devi solo tenere presente che quelle esecuzioni GC (in genere una per la vecchia e una per la nuova generazione) non sono su intervalli regolari, quindi è necessario estrarre anche l'ora di inizio per la stampa (o si traccia contro un numero di sequenza, per la maggior parte degli scopi pratici che sarebbe sufficiente per la stampa).

Ad esempio su Oracle HotSpot VM con ParNewGC, c'è un MBean JMX chiamato java.lang:type=GarbageCollector,name=PS Scavenge, ha un attributo LastGCInfo, restituisce un CompositeData dell'ultima esecuzione di scavenger YG. È registrato con duration, assoluto startTime e memoryUsageBefore e memoryUsageAfter.

Basta usare un timer per leggere quell'attributo. Ogni volta che viene visualizzato un nuovo startTime, si sa che descrive un nuovo evento GC, si estraggono le informazioni sulla memoria e si continua a eseguire il polling per il prossimo aggiornamento. (Non sono sicuro che un AttributeChangeNotification possa essere usato in qualche modo.)

Suggerimento: nel timer è possibile misurare la distanza dal ultima esecuzione di GC, e se è troppo lungo per il risultato del plotting, è possibile invocare System.gc () condizionatamente. Ma non lo farei in un'istanza OLTP.

 2
Author: eckes, 2012-08-15 19:14:53

Come è stato suggerito, prova VisualVM per ottenere una vista di base.

Puoi anche usare Eclipse MAT, per fare un'analisi della memoria più dettagliata.

Va bene fare un Sistema.gc() a patto che tu non dipenda da esso, per la correttezza del tuo programma.

 0
Author: Aakash, 2009-06-29 19:14:54

Il problema con il sistema.gc, è che la JVM assegna già automaticamente il tempo al garbage collector in base all'utilizzo della memoria.

Tuttavia, se si sta, ad esempio, lavorando in una condizione di memoria molto limitata, come un dispositivo mobile, Sistema.gc consente di allocare manualmente più tempo verso questa garbage collection, ma a costo del tempo della cpu (ma, come hai detto, non sei così preoccupato per i problemi di prestazioni di gc).

La migliore pratica sarebbe probabilmente essere usalo solo dove potresti fare grandi quantità di deallocazione (come svuotare un array di grandi dimensioni).

Tutto considerato, dal momento che sei semplicemente preoccupato per l'utilizzo della memoria, sentiti libero di chiamare gc, o, meglio ancora, vedere se fa molta differenza di memoria nel tuo caso, e poi decidere.

 0
Author: bgw, 2009-06-29 22:04:03

Aggiungendo alla lista delle risposte, JConsole (incluso nella directory jdk/bin) è anche una buona interfaccia da provare.

Riferimento

 0
Author: Ankit, 2017-04-11 14:01:53