1. JMX (Java Management Extensions): il cuore del monitoraggio della JVM
Il monitoraggio è come un check-up regolare per la tua applicazione. Se il logging può essere paragonato a un diario in cui si annota tutto ciò che è già accaduto, il monitoraggio è un insieme di strumenti che mostrano lo stato del sistema in questo momento: temperatura, battito, pressione, livello di zucchero e altri indicatori vitali della JVM.
Aiuta a capire quanta memoria è realmente utilizzata e se ci sono perdite, quanti thread stanno lavorando e in quale stato si trovano — in attesa, in esecuzione o bloccati. Puoi vedere quanto spesso si attiva il garbage collector, quanto è caricato il processore e notare in tempo segnali preoccupanti come un improvviso aumento dell’uso di memoria o del numero di thread.
In breve, il logging racconta cosa è già successo, mentre il monitoraggio mostra cosa sta succedendo adesso.
Basi di JMX: che cos’è e a cosa serve
JMX è una tecnologia in Java che permette di osservare la vita della tua applicazione dall’interno e persino di gestirla un po’. Funziona tramite oggetti speciali — gli MBean (Management Bean). Possiamo dire che sono come “sensori” e “interruttori” all’interno della JVM: alcuni mostrano lo stato del sistema, altri permettono di regolare qualcosa.
Con JMX puoi sapere quanta memoria è attualmente allocata alla JVM, quanti thread sono attivi, quanto tempo impiega il garbage collector e molto altro — senza dover toccare il codice o riavviare l’applicazione.
Come funziona
Nella JVM, di default, sono già presenti numerosi MBean che forniscono informazioni su:
- memoria (heap, non-heap);
- garbage collector (GC);
- thread;
- classi (quante caricate, quante scaricate);
- e persino sulla stessa JVM (versione, parametri di avvio).
JMX è come il cruscotto di un’auto. Vedi velocità, giri, temperatura del motore — e tutto questo è disponibile tramite sensori standard (MBean).
Come accedere a JMX
Il modo più semplice è usare l’utilità standard JConsole, inclusa nel JDK.
Avvio di JConsole
- Apri il terminale/la riga di comando.
- Esegui il comando:
jconsole - Seleziona il processo Java che vuoi monitorare (ad esempio, la tua applicazione).
JConsole si connetterà alla JVM tramite JMX e mostrerà grafici e tabelle: utilizzo della memoria, numero di thread, attività del garbage collector e così via.
Esempio: visualizzare memoria e thread
In JConsole apri le schede "Memory" e "Threads". Vedrai come cambia la quantità di memoria utilizzata, quanti thread sono in vita al momento, quali sono attivi e quali in attesa.
MBean personalizzati
Puoi creare i tuoi MBean per monitorare metriche personalizzate (ad esempio, il numero di ordini elaborati). Ma questo è un argomento avanzato: gli MBean standard forniscono già moltissime informazioni.
2. VisualVM — monitoraggio visivo e profilazione
Se JConsole è un “cruscotto”, allora VisualVM è un intero centro diagnostico con radiografie, risonanza magnetica ed esami del sangue. Consente non solo di monitorare, ma anche di profilare l’applicazione, acquisire heap dump, analizzare le perdite e vedere quali metodi richiedono più tempo.
Installazione e avvio di VisualVM
- VisualVM è incluso nella distribuzione del JDK (di solito come jvisualvm), ma la versione più recente si può scaricare da visualvm.github.io.
- Si avvia con il comando:
jvisualvm - Dopo l’avvio vedrai l’elenco di tutti i processi Java in esecuzione sulla tua macchina.
Connessione a un processo
- Trova il tuo processo (ad esempio, Main o MyApp) nell’elenco.
- Fai doppio clic su di esso — si aprirà una scheda con le informazioni sul processo.
- Fatto! Ora vedi:
- Uso di CPU e memoria in tempo reale.
- Numero di thread e il loro stato.
- Elenco delle classi caricate.
- La possibilità di acquisire heap dump e thread dump.
Funzionalità principali di VisualVM
Con VisualVM puoi osservare come viene utilizzata la memoria — sia heap sia non-heap. Il grafico mostra se il consumo cresce o si stabilizza. Per verificare il lavoro del garbage collector, premi il pulsante "Perform GC" — la JVM proverà subito a ripulire la memoria. Puoi creare un heap dump (istantanea della memoria) e studiarlo per cercare perdite.
Lo strumento mostra anche lo stato dei thread: quanti sono avviati, quali lavorano, attendono o sono bloccati. Se si verifica un deadlock, VisualVM aiuta a rilevarlo e a mostrare le interdipendenze.
Per un’analisi approfondita c’è la profilazione: vedrai i metodi “caldi” che “mangiano” più tempo di CPU o memoria. Utile per diagnosticare cali inaspettati di prestazioni.
Esempio: monitoriamo una mini‑applicazione
public class MemoryLeakDemo {
public static void main(String[] args) throws InterruptedException {
List<byte[]> memoryConsumers = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
memoryConsumers.add(new byte[1024 * 1024]); // 1 MB
Thread.sleep(100); // Aspettiamo un po' per rendere il grafico più uniforme
}
System.out.println("Fatto! Non dimenticare di dare un'occhiata in VisualVM :)");
Thread.sleep(60000); // Manteniamo l'applicazione aperta per l'analisi
}
}
Ora:
- Avvia il programma.
- Apri VisualVM e connettiti al processo.
- Osserva come cresce l’utilizzo della memoria.
- Acquisisci un heap dump, trova gli array che occupano memoria.
3. Java Flight Recorder (JFR): la «scatola nera» per la JVM
Che cos’è JFR
Java Flight Recorder è uno strumento integrato nella JVM per raccogliere eventi dettagliati sul funzionamento dell’applicazione. È una «scatola nera»: JFR registra ciò che accade nella JVM per trovare in seguito colli di bottiglia o le cause di un incidente.
JFR raccoglie:
- eventi di GC;
- informazioni sui thread;
- frequenza delle chiamate ai metodi e profili temporali;
- pause e latenze;
- eccezioni ed errori.
Come abilitare JFR
A partire da Java 11+ JFR è presente direttamente in OpenJDK.
Avvio con JFR
java -XX:StartFlightRecording=filename=recording.jfr,duration=60s,settings=profile -jar MyApp.jar
- filename=recording.jfr — dove salvare la registrazione.
- duration=60s — per quanto registrare.
- settings=profile — livello di dettaglio (default, profile, continuous).
Visualizzazione dei risultati
Per analizzare il file .jfr si utilizza JDK Mission Control (JMC):
- Scaricare JMC: jdk.java.net/jmc
- Aprire il file recording.jfr.
- Esaminare grafici, metodi “caldi”, pause di GC e attività dei thread.
Esempio: registriamo la «scatola nera»
- Avvia l’applicazione con JFR (vedi il comando sopra).
- Apri JDK Mission Control e carica il file di registrazione.
- Valuta i “punti caldi” su CPU/memoria, la frequenza delle raccolte di garbage e il numero di thread attivi.
4. Pratica: monitoriamo un’applicazione
import java.util.ArrayList;
import java.util.List;
public class MonitoringExample {
public static void main(String[] args) throws InterruptedException {
List<byte[]> memory = new ArrayList<>();
for (int i = 0; i < 50; i++) {
memory.add(new byte[2 * 1024 * 1024]); // 2 MB
Thread.sleep(500);
}
// Avviamo un thread
new Thread(() -> {
while (true) {
try {
Thread.sleep(1000);
System.out.println("Il thread in background è in esecuzione...");
} catch (InterruptedException e) {
break;
}
}
}).start();
Thread.sleep(20000); // Manteniamo l'applicazione aperta per il monitoraggio
}
}
Azioni:
- Avvia il programma.
- Apri VisualVM, trova il processo e guarda il grafico della memoria e i thread.
- Prova ad acquisire un heap dump e un thread dump.
- Per utenti avanzati: avvia con JFR e guarda i risultati in JMC.
5. Suggerimenti utili
Tabella comparativa degli strumenti di monitoraggio
| Strumento | Per cosa è adatto | Come avviare | Caratteristiche |
|---|---|---|---|
| JConsole (JMX) | Metriche di base della JVM, thread, GC | |
Semplice, incluso nel JDK |
| VisualVM | Monitoraggio, profilazione, heap dump | |
Grafici, analisi della memoria, CPU |
| Java Flight Recorder | Analisi approfondita degli eventi della JVM | |
Analisi in JMC, «scatola nera» |
| JDK Mission Control | Visualizzazione dei file JFR | programma separato | Analisi dettagliata, report |
Raccomandazioni
- Monitora non solo in produzione, ma anche in fase di test. Così intercetterai prima le perdite di memoria e i thread bloccati.
- L’heap dump non fa male! Esegui un dump della memoria in caso di sospetta perdita e analizzalo in VisualVM.
- Non temere di sperimentare con JFR. Anche se non tutto è chiaro subito, eventi e grafici aiutano a trovare i colli di bottiglia.
- JMX può essere usato via codice. Ad esempio, per inviare metriche a Prometheus/Grafana.
- La profilazione non è per l’uso continuo. Attiva i profiler in modo mirato, altrimenti l’applicazione può rallentare.
6. Errori tipici nel monitoraggio della JVM
Errore n. 1: non monitorare affatto. Molti principianti pensano che se l’applicazione “funziona”, allora va tutto bene. In realtà, i problemi con memoria e thread spesso si manifestano sotto carico o col passare del tempo. Non essere pigro: apri VisualVM/JConsole almeno periodicamente.
Errore n. 2: acquisire un heap dump su applicazioni enormi senza preparazione. Un heap dump di una grande applicazione può pesare gigabyte e “congelare” il processo per alcuni secondi. Fallo in un ambiente di test o nelle ore di minor traffico se si tratta della produzione.
Errore n. 3: ignorare le metriche di GC e dei thread. Una quota di tempo costantemente alta sul GC è un campanello d’allarme! E se il numero di thread cresce stabilmente — cerca una perdita di thread.
Errore n. 4: non analizzare i risultati del monitoraggio. Limitarsi ad aprire VisualVM non basta. Guarda quali oggetti occupano memoria, quali metodi “mangiano” CPU, perché si verificano i deadlock. Analizza gli stack trace e le cause.
Errore n. 5: usare i profiler in produzione senza cognizione. La profilazione può rallentare sensibilmente l’applicazione. Attivala solo per la diagnostica, non in modo permanente.
GO TO FULL VERSION