0Pricing
Java Academy · Lekcja

Dlaczego JMH

Unikanie naiwnych błędów w benchmarkach

Dlaczego JMH to bezpłatna lekcja Java Academy na CoddyKit. To lekcja 1 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Java Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Java Academy zawiera 4 lekcji w sumie.

Dlaczego JMH

Java Microbenchmark Harness (JMH) to standardowe narzędzie do pomiaru wydajności małych fragmentów kodu Java. Ręcznie tworzone pętle pomiarowe niemal zawsze podają nieprawidłowe wyniki, ponieważ JVM jest zaawansowanym środowiskiem uruchomieniowym wykonującym optymalizacje.

JMH służy do eliminowania tych problemów.

Naiwny benchmark

Typowa pierwsza próba polega na opakowaniu pętli w wywołania System.nanoTime(). Wygląda to rozsądnie, ale w przypadku mikrobenchmarków jest poważnie błędne.

public class Main {
    static int compute(int n) { return n * n + 7; }
    public static void main(String[] args) {
        long start = System.nanoTime();
        int sink = 0;
        for (int i = 0; i < 1_000_000; i++) sink = compute(i);
        long elapsed = System.nanoTime() - start;
        System.out.println("ns: " + elapsed + " sink=" + sink);
    }
}

Problem 1: Rozgrzewka JIT

JVM uruchamia się w trybie interpretowanym i dopiero po tysiącach wywołań kompiluje często wykonywane metody do kodu natywnego. Naiwny benchmark mierzy wolną fazę interpretowaną połączoną z szybką fazą skompilowaną, co prowadzi do pozbawionych znaczenia średnich.

JMH rozwiązuje ten problem za pomocą oddzielnej fazy rozgrzewki, której wyniki są odrzucane.

Problem 2: Eliminacja martwego kodu

Jeśli obliczony wynik nie jest nigdy używany, JIT może całkowicie usunąć obliczenia. Benchmark mierzy wtedy pustą pętlę.

JMH udostępnia zwracanie wartości oraz obiekt Blackhole, aby temu zapobiec.

Problem 3: Constant folding

Jeśli dane wejściowe są stałymi znanymi w czasie kompilacji, JIT oblicza wynik raz i używa go ponownie. W poniższym przykładzie kompilator może zastąpić całą pętlę pojedynczą stałą.

JMH używa obiektów @State, dzięki czemu optymalizator nie zna wartości wejściowych.

public class Main {
    public static void main(String[] args) {
        // 2 * 21 is constant; the JIT folds it to 42
        int result = 2 * 21;
        System.out.println(result);
    }
}

Problem 4: Optymalizacje pętli

JIT rozwija pętle, wynosi kod niezmienny poza pętle i wektoryzuje operacje. Ręcznie napisana pętla mierzy wtedy te optymalizacje, a nie operację, którą zamierzali Państwo przetestować.

JMH zastępuje Państwa pętlę starannie kontrolowanymi licznikami iteracji, którymi zarządza samodzielnie.

Problem 5: On-stack replacement

Długo wykonywana pętla w main może zostać skompilowana w trakcie wykonywania (on-stack replacement), co prowadzi do charakterystyki wydajności innej niż w przypadku normalnie skompilowanej metody. Powoduje to nieprzewidywalne zniekształcenie wyników.

Co zapewnia JMH

  • Oddzielne, odrzucane iteracje rozgrzewkowe.
  • Wiele iteracji pomiarowych wraz ze statystykami.
  • Uruchamianie w nowych JVM, aby uniknąć zanieczyszczenia profili.
  • Blackhole i zwracanie wyników chroniące przed eliminacją martwego kodu.
  • Obiekty @State zapobiegające constant folding.

Jak uruchomić benchmark

JMH jest oddzielną zależnością (org.openjdk.jmh) i zwykle uruchamia się je za pomocą procesora adnotacji oraz kompilacji Maven/Gradle, która tworzy wykonywalny plik JAR. Benchmarków nie uruchamia się z użyciem zwykłego main, tak jak zwykłego kodu.

Statystyki mają znaczenie

JMH podaje nie tylko średnią, lecz także błąd / przedział ufności obliczony na podstawie iteracji i forków. Wynik 42.0 +/- 1.3 ns/op informuje zarówno o wartości centralnej, jak i o skali jej zmienności — jest to niezbędne, aby ufać pomiarowi.

Kiedy sięgnąć po JMH

JMH należy używać podczas porównywania dwóch implementacji często wykonywanej ścieżki, weryfikowania optymalizacji lub mierzenia operacji trwających od nanosekund do mikrosekund. W przypadku zadań trwających całe sekundy, takich jak operacje wejścia-wyjścia czy komunikacja sieciowa, zwykle wystarcza pomiar czasu zegarowego.

Szybki test

Proszę sprawdzić zrozumienie, dlaczego JMH jest potrzebne.

Podsumowanie

Nauczyli się Państwo, dlaczego mikrobenchmarki wymagają odpowiedniego narzędzia:

  • JVM przechodzi rozgrzewkę: kod interpretowany staje się skompilowany dopiero po wielu wywołaniach.
  • Eliminacja martwego kodu i constant folding mogą usuwać obliczenia lub wykonywać je z wyprzedzeniem.
  • Optymalizacje pętli i on-stack replacement zniekształcają wyniki ręcznie napisanych pętli.
  • JMH dodaje rozgrzewkę, iteracje pomiarowe, forkowanie, Blackhole i statystyki.
  • Warto po nie sięgnąć podczas mierzenia często wykonywanych ścieżek trwających nanosekundy.

Często zadawane pytania

Czy lekcja „Dlaczego JMH” jest bezpłatna?

Tak — pełny tekst „Dlaczego JMH” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Java Academy, przejdź na CoddyKit PRO. Kurs Java Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Dlaczego JMH”?

Unikanie naiwnych błędów w benchmarkach Ćwiczysz Java Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Java Academy?

Nie wymagamy żadnego doświadczenia. Java Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 1 z 4.

Ile czasu zajmuje lekcja „Dlaczego JMH”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Java Academy?

Tak. Każda lekcja Java Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Dlaczego JMH
  2. Pisanie benchmarku
  3. Rozgrzewka i iteracje
  4. Unikanie eliminacji martwego kodu
← Powrót do Java Academy