1. JMX (Java Management Extensions): serce monitorowania JVM
Monitoring to jak regularne badania kontrolne dla twojej aplikacji. Jeśli logowanie można porównać do dziennika, gdzie zapisuje się wszystko, co już się wydarzyło, to monitorowanie to zestaw przyrządów pokazujących stan systemu tu i teraz: temperaturę, puls, ciśnienie, poziom cukru i inne kluczowe wskaźniki życiowe JVM.
Pozwala zrozumieć, ile pamięci jest faktycznie używane i czy nie „cieknie”, ile wątków pracuje i w jakim są stanie — czekają, wykonują się czy są zablokowane. Można zobaczyć, jak często uruchamia się garbage collector, jak obciążony jest procesor i w porę zauważyć niepokojące symptomy, takie jak nagły wzrost zużycia pamięci lub liczby wątków.
W skrócie: logowanie opowiada, co już się wydarzyło, a monitorowanie pokazuje, co dzieje się właśnie teraz.
Podstawy JMX: co to jest i po co
JMX to technologia w Javie, która pozwala zaglądać do wnętrza twojej aplikacji i nawet trochę nią zarządzać. Działa przez specjalne obiekty — MBean (Management Bean). Można powiedzieć, że to „czujniki” i „przełączniki” w środku JVM: jedne pokazują stan systemu, inne pozwalają coś podkręcić.
Za pomocą JMX możesz dowiedzieć się, ile pamięci jest obecnie przydzielone JVM, ile wątków jest aktywnych, ile czasu zajmuje garbage collection i wiele więcej — bez potrzeby grzebania w kodzie czy restartu aplikacji.
Jak to działa
W JVM w standardzie jest już wiele MBean‑ów, które dostarczają informacji o:
- pamięci (heap, non-heap);
- kolektorach GC;
- wątkach;
- klasach (ile załadowano, ile zwolniono);
- a nawet o samej JVM (wersja, parametry uruchomienia).
JMX to jak deska rozdzielcza w samochodzie. Widzisz prędkość, obroty, temperaturę silnika — i wszystko to dostępne jest przez standardowe czujniki (MBean-y).
Jak uzyskać dostęp do JMX
Najprostszy sposób — użyć standardowego narzędzia JConsole, które wchodzi w skład JDK.
Uruchomienie JConsole
- Otwórz terminal/wiersz poleceń.
- Wykonaj polecenie:
jconsole - Wybierz proces Javy, który chcesz monitorować (np. swoją aplikację).
JConsole połączy się z JVM przez JMX i pokaże wykresy oraz tabele: użycie pamięci, liczbę wątków, aktywność garbage collectora itd.
Przykład: podgląd pamięci i wątków
W JConsole otwórz karty "Memory" i "Threads". Zobaczysz, jak zmienia się ilość używanej pamięci, ile wątków aktualnie żyje, które są aktywne, a które czekają.
Własne MBean-y
Można tworzyć własne MBean-y do monitorowania własnych metryk (np. liczby przetworzonych zamówień). To jednak temat dla zaawansowanych: standardowe MBean-y dostarczają bardzo dużo informacji.
2. VisualVM — wizualne monitorowanie i profilowanie
Jeśli JConsole to „deska rozdzielcza”, to VisualVM jest całym centrum diagnostycznym z RTG, MRI i badaniami krwi. Pozwala nie tylko monitorować, ale i profilować aplikację, wykonywać heap dump, analizować wycieki i widzieć, które metody zajmują najwięcej czasu.
Instalacja i uruchomienie VisualVM
- VisualVM wchodzi w skład JDK (zwykle jako jvisualvm), ale najnowszą wersję można pobrać z visualvm.github.io.
- Uruchamia się poleceniem:
jvisualvm - Po uruchomieniu zobaczysz listę wszystkich procesów Javy uruchomionych na twojej maszynie.
Połączenie z procesem
- Znajdź swój proces (np. Main lub MyApp) na liście.
- Kliknij go dwukrotnie — otworzy się karta z informacjami o procesie.
- Gotowe! Teraz zobaczysz:
- Użycie CPU i pamięci w czasie rzeczywistym.
- Liczbę wątków i ich stan.
- Listę załadowanych klas.
- Możliwość wykonania heap dump i thread dump.
Najważniejsze możliwości VisualVM
Za pomocą VisualVM można obserwować użycie pamięci — zarówno heap, jak i non-heap. Na wykresie widać, czy zużycie rośnie, czy się stabilizuje. Aby sprawdzić działanie garbage collectora, kliknij przycisk "Perform GC" — JVM od razu spróbuje oczyścić pamięć. Można wykonać heap dump (zrzut pamięci) i zbadać go w poszukiwaniu wycieków.
Narzędzie pokaże też stan wątków: ile jest uruchomionych, które pracują, czekają lub są zablokowane. Jeśli wystąpi deadlock, VisualVM pomoże go wykryć i pokazać wzajemne blokady.
Do pogłębionej analizy służy profilowanie: zobaczysz „gorące” metody, które „zjadają” najwięcej czasu procesora lub pamięci. Jest to pomocne przy diagnozowaniu niespodziewanych spadków wydajności.
Przykład: monitorujemy miniaplikację
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); // Chwilę poczekamy, aby wykres był gładszy
}
System.out.println("Gotowe! Nie zapomnij zajrzeć do VisualVM :)");
Thread.sleep(60000); // Trzymamy aplikację otwartą do analizy
}
}
Teraz:
- Uruchom program.
- Otwórz VisualVM, połącz się z procesem.
- Obserwuj, jak rośnie użycie pamięci.
- Wykonaj heap dump, znajdź tablice zajmujące pamięć.
3. Java Flight Recorder (JFR): czarna skrzynka dla JVM
Czym jest JFR
Java Flight Recorder to wbudowane w JVM narzędzie do zbierania szczegółowych zdarzeń z pracy aplikacji. To „czarna skrzynka”: JFR zapisuje, co dzieje się w JVM, aby później znaleźć wąskie gardła lub przyczyny incydentu.
JFR zbiera:
- zdarzenia GC;
- informacje o wątkach;
- częstotliwość wywołań metod i profile czasowe;
- pauzy i opóźnienia;
- wyjątki i błędy.
Jak włączyć JFR
Od Javy 11+ JFR jest wbudowany w OpenJDK.
Uruchomienie z JFR
java -XX:StartFlightRecording=filename=recording.jfr,duration=60s,settings=profile -jar MyApp.jar
- filename=recording.jfr — gdzie zapisać nagranie.
- duration=60s — jak długo nagrywać.
- settings=profile — poziom szczegółowości (default, profile, continuous).
Przegląd wyników
Do analizy pliku .jfr używa się JDK Mission Control (JMC):
- Pobierz JMC: jdk.java.net/jmc
- Otwórz plik recording.jfr.
- Przeanalizuj wykresy, „gorące” metody, pauzy GC i aktywność wątków.
Przykład: nagrywamy „czarną skrzynkę”
- Uruchom aplikację z JFR (zob. polecenie powyżej).
- Otwórz JDK Mission Control, załaduj plik nagrania.
- Oceń „gorące” miejsca pod kątem CPU/pamięci, częstotliwość zbiórek śmieci i liczbę aktywnych wątków.
4. Praktyka: monitorujemy aplikację
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);
}
// Uruchamiamy wątek
new Thread(() -> {
while (true) {
try {
Thread.sleep(1000);
System.out.println("Wątek w tle działa...");
} catch (InterruptedException e) {
break;
}
}
}).start();
Thread.sleep(20000); // Trzymamy aplikację otwartą do monitorowania
}
}
Czynności:
- Uruchom program.
- Otwórz VisualVM, znajdź proces, spójrz na wykres pamięci i wątki.
- Spróbuj wykonać heap dump i thread dump.
- Dla zaawansowanych: uruchom z JFR i obejrzyj wyniki w JMC.
5. Przydatne szczegóły
Tabela porównawcza narzędzi do monitorowania
| Narzędzie | Do czego służy | Jak uruchomić | Cechy |
|---|---|---|---|
| JConsole (JMX) | Podstawowe metryki JVM, wątki, GC | |
Proste, wchodzi w skład JDK |
| VisualVM | Monitorowanie, profilowanie, heap dump | |
Wykresy, analiza pamięci i CPU |
| Java Flight Recorder | Dogłębna analiza zdarzeń JVM | |
Analiza w JMC, „czarna skrzynka” |
| JDK Mission Control | Przegląd plików JFR | oddzielny program | Szczegółowa analityka, raporty |
Zalecenia
- Monitoruj nie tylko na produkcji, ale też na etapie testów. Dzięki temu wcześniej wyłapiesz wycieki pamięci i „zawieszone” wątki.
- Heap dump — to nie boli! Rób zrzut pamięci przy podejrzeniu wycieku i analizuj go w VisualVM.
- Nie bój się eksperymentować z JFR. Nawet jeśli nie wszystko jest od razu jasne, zdarzenia i wykresy pomogą znaleźć wąskie gardła.
- JMX można wykorzystywać programowo. Na przykład do wysyłania metryk do Prometheus/Grafana.
- Profilowanie nie jest do pracy ciągłej. Włączaj profilery punktowo, w przeciwnym razie aplikacja może zwolnić.
6. Typowe błędy przy monitorowaniu JVM
Błąd nr 1: W ogóle nie monitorować. Wielu początkujących uważa, że skoro aplikacja „działa”, to wszystko jest w porządku. W praktyce problemy z pamięcią i wątkami często ujawniają się pod obciążeniem lub po czasie. Nie zaniedbuj otwierania VisualVM/JConsole choćby okresowo.
Błąd nr 2: Zrzucać heap dump w ogromnych aplikacjach bez przygotowania. Heap dump dużej aplikacji może ważyć gigabajty i „zamrozić” proces na kilka sekund. Rób to w środowisku testowym albo w „cichych” godzinach, jeśli mowa o produkcji.
Błąd nr 3: Ignorować wskaźniki GC i wątków. Stale wysoki odsetek czasu poświęcony na GC to sygnał alarmowy! A jeśli liczba wątków stale rośnie — szukaj wycieku wątków.
Błąd nr 4: Nie analizować wyników monitorowania. Samo otwarcie VisualVM to za mało. Sprawdzaj, które obiekty zajmują pamięć, które metody „pożerają” CPU, dlaczego pojawiają się deadlock‑i. Analizuj stack trace’y i przyczyny.
Błąd nr 5: Używać profilerów na produkcji bez zrozumienia. Profilowanie może znacząco spowolnić aplikację. Włączaj je tylko do diagnostyki, a nie „na stałe”.
GO TO FULL VERSION