2009-06-29 11 views
50

Abbiamo un'applicazione j2ee in esecuzione su Jboss e vogliamo monitorare l'utilizzo della memoria. Attualmente viene utilizzato il seguente codiceCome monitorare l'utilizzo della memoria Java?

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

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

alt text

Un consulente ci ha detto che chiama gc() è esplicitamente sbagliato "lasciare che JVM decidere quando eseguire gc". Fondamentalmente i suoi argomenti erano gli stessi di disscussed here. Ma ancora non capisco:

  • come posso avere la mia curva di utilizzo della memoria?
  • Cosa c'è di sbagliato con l'esplicito gc()? Non mi importa dei piccoli problemi di prestazioni che possono verificarsi con gc esplicito() e che stimerei nell'1-3%. Ciò di cui ho bisogno è il monitoraggio della memoria e del filo che mi aiuta nell'analisi del nostro sistema sul sito del cliente.
+1

monitor con jvisualvm - fornisce statistiche migliori. –

risposta

47

Se si vuole veramente vedere cosa sta succedendo nella memoria della VM, è necessario utilizzare uno strumento valido come VisualVM. Questo software è gratuito ed è un ottimo modo per vedere cosa sta succedendo.

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

+1

Appena guardato VisualVM - è dolce. –

+4

System.gc() può danneggiare le prestazioni perché interferisce con gli algoritmi del GC. Questo può degradare tutti i GC successivi. –

+2

[citazione necessaria] Vuoi dimostrare la tua richiesta? Si prega di spiegare come effettuare una chiamata a gc() "interferisce" con gli algoritmi di garbage collector e come una chiamata a un metodo "degrada" le chiamate successive? – amischiefr

9

Direi che il consulente ha ragione nella teoria e hai ragione nella pratica. Come saying goes:

In teoria, teoria e pratica sono le stesse. In pratica, non lo sono.

Le specifiche Java indicano che System.gc suggerisce di chiamare la garbage collection. In pratica, genera appena un thread e viene eseguito immediatamente su Sun JVM.

Sebbene in teoria si possa incasinare un'implementazione JRM della raccolta dei dati estremamente accurata, a meno che non si stia scrivendo codice generico destinato a essere distribuito su qualsiasi JVM, non preoccupatevi. Se funziona per te, fallo.

+0

sai se questo comportamento _farca un thread e viene eseguito immediatamente_ è anche applicabile alla JVM attuale (Sun/Oracle/Hotspot) (8)? – Ben

+1

In esecuzione System.gc spesso, solo per ottenere statistiche sensibili sull'utilizzo della memoria, * farà male le prestazioni. Quindi non è un "basta farlo". System.gc() è ragionevole in casi come "OK, ora è stato fatto un grande lavoro che richiedeva molta memoria, e non ho molto da fare in questo momento, quindi raccolgo i rifiuti per migliorare le prestazioni delle raccolte di rifiuti secondarie in seguito". –

5

Date un'occhiata ai args JVM: http://java.sun.com/javase/technologies/hotspot/vmoptions.jsp#DebuggingOptions

XX: i messaggi di stampa -PrintGC alla raccolta dei rifiuti. Gestibile.

-XX: -PrintGCDettagli Stampa ulteriori dettagli nella garbage collection. Maneggevole. (Introdotto in 1.4.0.)

-XX: -PrintGCTimeStamps Stampa data e ora nella garbage collection. Maneggevole (Introdotto in 1.4.0.)

-XX: -PrintTenuringDistribution Stampa informazioni sul periodo di permanenza.

Mentre non si ha intenzione di stravolgere la JVM con chiamate esplicite a System.gc(), è possibile che non abbiano l'effetto previsto. Per capire veramente cosa sta succedendo con la memoria in una JVM con leggere tutto e tutto ciò che scrive Brian Goetz.

28

ci sono strumenti che consentono di monitorare l'utilizzo della memoria della VM. Il VM can expose memory statistics using JMX. È inoltre possibile print GC statistics per vedere come la memoria si sta eseguendo nel tempo.

Invocare System.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 riduzione dell'efficienza della memoria, tempi di GC più lunghi e una diminuzione dei colpi di cache (per le cache che utilizzano i riferimenti deboli). Sono d'accordo con il tuo consulente: System.gc() è cattivo. Andrei fino a disable it utilizzando l'interruttore della riga di comando.

+2

+1 per l'eccellente commento sulla promozione prematura. –

5

L'esecuzione in modo esplicito di System.gc() su un sistema di produzione è una pessima idea. Se la memoria arriva a qualsiasi dimensione, l'intero sistema può bloccarsi mentre è in esecuzione un GC completo. Su un server multi-gigabyte, questo può facilmente essere molto evidente, a seconda di come è configurato jvm e di quanto spazio di testa ha, ecc. Ecc. - Ho visto pause di oltre 30 secondi. Un altro problema è che, chiamando GC in modo esplicito, non stai effettivamente controllando come JVM sta eseguendo il GC, in realtà lo stai alterando - a seconda di come hai configurato la JVM, la raccolta dei rifiuti viene raccolta quando appropriato e in genere incrementale (non esegue solo un GC completo quando esaurisce la memoria). Ciò che stamperai non sarà simile a quello che farà la JVM da solo - per una cosa probabilmente vedrai meno GC automatici/incrementali mentre cancellerai la memoria manualmente.

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

Si potrebbe avere una discussione che viene stampata gratuitamente e disponibile a intervalli ragionevoli, questo mostrerà l'utilizzo effettivo di mem.

+0

In che modo viene mitigato non chiamando System.gc()? Alla fine la garbage JVM si accumula quando si esaurisce la memoria, quindi non si verificherà il ritardo? (Questa è stata la mia esperienza, almeno). – Yishai

+0

La JVM consente di specificare da più algoritmi GC. Fanno tutti una specie di GC incrementale, e possono occasionalmente innescare un GC completo (non sono troppo attento ai dettagli, ma fondamentalmente solo quando devono - una specie di "ultima risorsa" tipo di cosa, ad esempio quando non c'è spazio sufficiente per creare una nuova copia di alcune sezioni di mem durante l'incremento gc). Se chiami regolarmente System.gc succederà molto più spesso. Stai essenzialmente creando la tua strategia di GC, che è "solo periodicamente esegui un GC completo". La JVM ha strategie migliori di questa. –

0

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

È inoltre possibile utilizzare Eclipse MAT, per eseguire un'analisi della memoria più dettagliata.

È normale eseguire un System.gc() finché non si dipende da esso, per la correttezza del programma.

0

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

Tuttavia, se, per esempio, lavorando in una condizione limitata molto memoria, come un dispositivo mobile, System.gc permette di allocare più tempo manualmente verso questo garbage collection, ma a costo di tempo CPU (ma , come hai detto, non sei preoccupato per i problemi di prestazioni di gc).

migliori prassi probabilmente essere quello di utilizzare solo là dove si potrebbe fare una grande quantità di deallocazione (come vampate di calore un grande array).

Considerato tutto, dal momento che si è semplicemente preoccupati dell'utilizzo della memoria, si senta libero di chiamare gc, o, meglio ancora, vedere se fa molta differenza di memoria nel tuo caso e poi decidere.

2

Se si utilizza il JMX fornito storia del GC corre è possibile utilizzare lo stesso prima/dopo i numeri, basta non dovete forzare un GC.

Devi solo ricordare che quei GC eseguiti (in genere uno per vecchio e uno per nuova generazione) non sono su intervalli regolari, quindi è necessario estrarre l'ora di inizio per il tracciamento (o si trama contro una sequenza numero, per la maggior parte degli scopi pratici che sarebbe sufficiente per il tracciamento).

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

Basta usare un timer per leggere quell'attributo. Ogni volta che si presenta una nuova ora iniziale, 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 sia possibile utilizzare un AttributeChangeNotification

Suggerimento: nel tuo timer puoi misurare la distanza dall'ultima esecuzione del GC, e se è troppo lungo per la risoluzione del tuo disegno, puoi invocare Sistema. gc() condizionalmente. Ma non lo farei in un'istanza OLTP.

9

È possibile dare un'occhiata a stagemonitor. È un monitor delle prestazioni delle applicazioni java (web) open source. Cattura le metriche del tempo di risposta, le metriche JVM, i dettagli delle richieste (incluso uno stack di chiamate acquisito dal profiler della richiesta) e altro ancora. Il sovraccarico è molto basso.

Opzionalmente, è possibile utilizzare la grande grafite del database di timeseries con esso per archiviare una lunga cronologia di punti dati che è possibile guardare con cruscotti di fantasia.

Esempio: JVM Memory Dashboard

Date un'occhiata al project website per vedere le immagini, descrizioni delle funzioni e la documentazione.

Nota: Io sono l'autore di stagemonitor

+1

grazie, darò un'occhiata a questo. –

0

Aggiungendo alla lista delle risposte, JConsole (incluso nella directory JDK/bin) è un anche un bene interfaccia per provare.

Reference

Problemi correlati