Pomiar wydajności
Profilery, ślady i testy porównawcze
Pomiar wydajności to bezpłatna lekcja Android 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 Android Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Android Academy zawiera 4 lekcji w sumie.
Najpierw mierz, potem optymalizuj
Złota zasada pracy nad wydajnością brzmi: najpierw mierz, nigdy nie zgaduj. Ludzkie przeczucia dotyczące tego, co działa wolno, niemal zawsze się mylą.
W tej lekcji poznasz narzędzia, które Android udostępnia do obserwowania wydajności: profilery, ślady systemowe i mikrobenchmarki. Gdy potrafisz mierzyć, każda optymalizacja staje się decyzją opartą na danych, a nie przeczuciem.
- Profilery pokazują w czasie rzeczywistym użycie procesora, pamięci i energii.
- Ślady systemowe dokładnie pokazują, na co przeznaczany jest czas każdej klatki.
- Benchmarki dostarczają powtarzalnych wyników, które można porównywać między kompilacjami.
Budżet 16 ms na klatkę
Na ekranie 60 Hz system rysuje nową klatkę co 16,67 ms. Jeśli aplikacja nie zdoła przygotować klatki w tym czasie, klatka zostaje pominięta, a użytkownik odczuwa zacinanie (przycięcia). Na urządzeniach 120 Hz budżet zmniejsza się do około 8 ms.
Praca nad wydajnością polega przede wszystkim na zmieszczeniu się w tym budżecie. Poniższy komentarz pokazuje obliczenie, które warto mieć w pamięci.
// Frame budget math
// 60 Hz -> 1000ms / 60 = 16.67ms per frame
// 90 Hz -> 1000ms / 90 = 11.11ms per frame
// 120 Hz -> 1000ms / 120 = 8.33ms per frame
//
// Exceed the budget on the UI thread = a dropped frame = visible jank.
fun frameBudgetMs(refreshHz: Int): Double = 1000.0 / refreshHz
fun main() {
println("60Hz -> %.2f ms".format(frameBudgetMs(60)))
println("120Hz -> %.2f ms".format(frameBudgetMs(120)))
}Profiler Android Studio
Profiler Android Studio (View > Tool Windows > Profiler) podłącza się do uruchomionej aplikacji i wyświetla na żywo osie czasu dla procesora, pamięci, energii i sieci.
- CPU: rejestruj ślady metod i ślady systemowe, aby znaleźć najbardziej obciążające ścieżki kodu.
- Memory: obserwuj alokacje i wykonuj zrzuty sterty, aby znaleźć wycieki.
- Energy: wykrywaj blokady wybudzenia i nadmiarowe zadania zużywające baterię.
Zawsze profiluj kompilację przygotowaną jak wersja release na prawdziwym urządzeniu. Kompilacje debug i emulatory dają mylące wyniki, ponieważ optymalizacje są wyłączone.
Macrobenchmark dla rzeczywistych scenariuszy
Biblioteka Jetpack Macrobenchmark mierzy całe ścieżki użytkownika (uruchamianie, przewijanie, nawigację) na prawdziwym urządzeniu i podaje stabilne metryki, takie jak czas renderowania klatek i czas uruchamiania.
Tworzy Pan test, który uruchamia aplikację i wykonuje określony przebieg; biblioteka uruchamia go wiele razy i podaje medianę oraz wartości z 99. percentyla.
@RunWith(AndroidJUnit4::class)
class StartupBenchmark {
@get:Rule val rule = MacrobenchmarkRule()
@Test
fun coldStartup() = rule.measureRepeated(
packageName = "com.example.app",
metrics = listOf(StartupTimingMetric()),
iterations = 5,
startupMode = StartupMode.COLD
) {
pressHome()
startActivityAndWait()
}
}Microbenchmark dla obciążającego kodu
Jeśli chce Pan sprawdzić, jak szybko działa pojedyncza funkcja, należy użyć biblioteki Microbenchmark. Wykonuje ona kod w ciasnej pętli, rozgrzewa JIT i podaje liczbę nanosekund na operację, po odfiltrowaniu zakłóceń.
Należy jej używać do parserów, serializatorów, sortowania oraz wszelkich pomocniczych operacji zależnych od CPU, które są często wywoływane.
@RunWith(AndroidJUnit4::class)
class JsonParseBenchmark {
@get:Rule val benchmarkRule = BenchmarkRule()
@Test
fun parseLargePayload() {
val raw = loadSampleJson()
benchmarkRule.measureRepeated {
val parsed = parseUsers(raw) // code under test
// assertEquals avoids the compiler dropping the result
assertTrue(parsed.isNotEmpty())
}
}
}Śledzenie systemowe za pomocą Perfetto
Śledzenie systemowe rejestruje działania każdego wątku i systemu, klatka po klatce. Profiler CPU w Android Studio może je rejestrować, a ślad można także przechwycić za pomocą adb i otworzyć w Perfetto (ui.perfetto.dev).
Ślad pokazuje nielubiane czerwone klatki, pracę w głównym wątku oraz czas spędzony w GPU. To najlepsze pojedyncze narzędzie do diagnozowania zacinania.
# Record a 5-second system trace from the command line
adb shell perfetto -o /data/misc/perfetto-traces/trace.perfetto-trace \
-t 5s sched freq idle am wm gfx view
# Pull it to your machine, then open in https://ui.perfetto.dev
adb pull /data/misc/perfetto-traces/trace.perfetto-traceNiestandardowe sekcje śladu
Domyślnie ślady pokazują pracę frameworka. Aby oznaczyć własny kod, należy umieścić go w nazwanej sekcji śladu. Nazwy te pojawią się jako oznaczone bloki w Perfetto, dzięki czemu łatwo będzie znaleźć miejsca powodujące największe obciążenie.
Należy używać API androidx.tracing, aby sekcje były widoczne zarówno w śladach debug, jak i benchmarków.
import androidx.tracing.trace
fun loadDashboard(repo: Repo): Dashboard {
return trace("loadDashboard") {
val user = trace("fetchUser") { repo.user() }
val feed = trace("fetchFeed") { repo.feed() }
Dashboard(user, feed)
}
}
// In Perfetto you will now see named slices:
// loadDashboard > fetchUser, fetchFeedŚledzenie pominiętych klatek w czasie działania
Profiler nie zawsze jest podłączony. JankStats to biblioteka Jetpack, która raportuje zacinające się klatki z poziomu uruchomionej aplikacji, dzięki czemu można je rejestrować lub wysyłać zagregowane dane do analityki.
Podłącza się ona do okna i wywołuje odpowiednią funkcję za każdym razem, gdy klatka przekroczy swój budżet.
val jankStats = JankStats.createAndTrack(window) { frameData ->
if (frameData.isJank) {
Log.w("Jank", "Janky frame: ${frameData.frameDurationUiNanos} ns")
analytics.logJank(frameData.frameDurationUiNanos)
}
}
// Pause/resume with your screen lifecycle
override fun onResume() { super.onResume(); jankStats.isTrackingEnabled = true }
override fun onPause() { super.onPause(); jankStats.isTrackingEnabled = false }Odczytywanie liczb: percentyle
Pojedyncza średnia może ukrywać problemy. Jeśli średnia klatka trwa 10 ms, ale 99. percentyl wynosi 40 ms, to 1% klatek się zacina i użytkownicy to odczuwają. Zawsze należy sprawdzać P50, P90, P99, a nie tylko średnią.
Benchmarki raportują te wartości automatycznie. Poniższy pomocniczy fragment pokazuje tę ideę na surowych próbkach klatek.
fun percentile(samplesMs: List<Double>, p: Int): Double {
val sorted = samplesMs.sorted()
val index = ((p / 100.0) * (sorted.size - 1)).toInt()
return sorted[index]
}
fun main() {
val frames = listOf(8.0, 9.0, 10.0, 9.5, 11.0, 40.0, 9.0, 10.5)
println("P50 = %.1f ms".format(percentile(frames, 50)))
println("P99 = %.1f ms".format(percentile(frames, 99)))
}Powtarzalny proces pomiaru
Wiarygodne wyniki wymagają zdyscyplinowanego procesu. Za każdym razem należy postępować zgodnie z tą listą kontrolną:
- Należy używać kompilacji release / non-debuggable (z włączonym R8).
- Należy uruchamiać aplikację na fizycznym urządzeniu, podłączonym do zasilania i o stabilnym stanie termicznym.
- Należy powtórzyć scenariusz kilka razy i podać medianę.
- Należy zmieniać jedną rzecz naraz i ponownie wykonać pomiar.
- Należy porównywać wyniki z zapisanym punktem odniesienia, aby móc potwierdzić poprawę.
Jeśli pominie Pan te kroki, będzie Pan ścigać szum pomiarowy zamiast naprawiać rzeczywiste problemy.
Gdzie naprawdę ucieka czas
Większość zacinania w Androidzie wynika z niewielkiego zestawu przyczyn. Ich znajomość podpowiada, na które narzędzia należy zwrócić uwagę:
- Praca w głównym wątku: operacje dyskowe, sieciowe i JSON w wątku interfejsu.
- Nadmierna rekompozycja: Compose przerysowuje zdecydowanie zbyt dużą część interfejsu.
- Częste alokacje: przerwy na zbieranie śmieci.
- Przebiegi układu: głęboko zagnieżdżone lub wielokrotnie mierzone układy.
W kolejnych lekcjach tego kursu bezpośrednio zajmiemy się rekompozycją, wyciekami pamięci i uruchamianiem aplikacji. To pomiary pokażą, który problem należy naprawić jako pierwszy.
Szybkie sprawdzenie
Chce Pan uzyskać stabilny i powtarzalny pomiar czasu trwania zimnego uruchamiania aplikacji na prawdziwym urządzeniu, wykonany podczas wielu uruchomień. Które narzędzie będzie najlepsze?
Podsumowanie: potrafi Pan już mierzyć
Nauczył się Pan uwidaczniać wydajność, zanim cokolwiek zostanie zmienione:
- Budżet 16 ms na klatkę wyznacza granicę między płynnością a zacinaniem.
- Profiler Android Studio pokazuje na żywo użycie procesora, pamięci i energii.
- Macrobenchmarki i Microbenchmarki dostarczają powtarzalnych wyników.
- Ślady Perfetto i niestandardowe sekcje
trace()pokazują, gdzie upływa czas. - JankStats raportuje zacinanie z poziomu uruchomionej aplikacji.
- Należy odczytywać P50/P90/P99, profilować kompilacje release na prawdziwych urządzeniach i zmieniać jedną rzecz naraz.
Teraz zastosujemy tę wiedzę do jednego z największych źródeł zacinania w Compose: rekompozycji.
Często zadawane pytania
Czy lekcja „Pomiar wydajności” jest bezpłatna?
Tak — pełny tekst „Pomiar wydajności” 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 Android Academy, przejdź na CoddyKit PRO. Kurs Android Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Pomiar wydajności”?
Profilery, ślady i testy porównawcze Ćwiczysz Android 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ąć Android Academy?
Nie wymagamy żadnego doświadczenia. Android 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 „Pomiar wydajności”?
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 Android Academy?
Tak. Każda lekcja Android 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
- Pomiar wydajności
- Poskramianie rekompozycji
- Wycieki pamięci i ich usuwanie
- Profile uruchamiania i Baseline Profiles