Android Runtime (ART) to środowisko wykonawcze aplikacji Android, wprowadzone w Android 5.0 Lollipop jako zamiennik Dalvik. Główna innowacja — wstępna kompilacja AOT kodu bajtowego DEX do natywnego kodu maszynowego bezpośrednio podczas instalacji aplikacji, co wyeliminowało wieloletni problem nagrzewania kompilatora JIT. Według Google, 2024, ART zapewnia wzrost wydajności do 20–30% w porównaniu z Dalvik przy zachowaniu pełnej wstecznej kompatybilności z formatem DEX.
Najważniejsze
Android Runtime (ART) to środowisko wykonawcze aplikacji, które kompiluje kod bajtowy DEX do natywnego kodu maszynowego przed uruchomieniem. W przeciwieństwie do Dalvik, która używała kompilacji Just-In-Time podczas działania, ART wykonuje kompilację Ahead-Of-Time (AOT) podczas instalacji APK. Ta fundamentalna zmiana architektury doprowadziła do znacznego przyspieszenia aplikacji i zmniejszenia zużycia energii.
ART po raz pierwszy pojawiło się jako opcja eksperymentalna w Android 4.4 KitKat. Programiści mogli włączyć ją w ustawieniach dla programistów i testować swoje aplikacje. W Android 5.0 Lollipop ART stało się domyślnym środowiskiem wykonawczym, a Dalvik zostało całkowicie usunięte z platformy. Do czasu wydania Android 7.0 Nougat ART otrzymało hybrydowy tryb kompilacji.
Decyzja o zastąpieniu Dalvik przez ART nie była nagła. Prace nad nowym środowiskiem rozpoczęły się w 2012 roku, gdy Google zdało sobie sprawę z ograniczeń podejścia JIT. Główne cele: przyspieszenie uruchamiania aplikacji, zmniejszenie obciążenia procesora i redukcja zużycia energii. Rozwojem kierował zespół Android Runtime Group, który wcześniej pracował nad optymalizacjami Dalvik.
ART używa tej samej architektury rejestrowej co Dalvik, ale z całkowicie przeprojektowanym kompilatorem. Zamiast interpretera i kompilatora JIT, ART zawiera kompilator AOT dex2oat, który przekształca pliki DEX w binarne pliki ELF podczas instalacji. W rezultacie aplikacja na ART uruchamia się natychmiast z natywną wydajnością, bez fazy nagrzewania.
ART zachowało kluczowe zasady Dalvik: izolację aplikacji poprzez oddzielne procesy, architekturę rejestrową i obsługę formatu DEX. Jednak wewnętrzna implementacja została całkowicie przepisana. Zamiast interpretera Dalvik, ART zawiera trzy tryby wykonawcze: interpreter, kompilator JIT i kompilator AOT dex2oat. Wybór trybu zależy od etapu cyklu życia aplikacji.
Kluczowym komponentem ART jest dex2oat (dalvik executable to optimized android translator). To narzędzie uruchamia się podczas instalacji aplikacji (od Android 7.0 — także podczas optymalizacji w tle). dex2oat odczytuje pliki DEX z APK, optymalizuje kod bajtowy i generuje plik OAT — binarny ELF z kodem natywnym. Pliki OAT są przechowywane w katalogu /data/dalvik-cache/.
# Sprawdzanie plików OAT na urządzeniu
adb shell ls -la /data/dalvik-cache/arm64/
# Wymuszona rekompilacja aplikacji
adb shell cmd package compile -m speed com.example.app
System ART składa się z kilku połączonych modułów. Kompilator dex2oat odpowiada za generowanie kodu natywnego. Moduł czyszczenia pamięci (GC) zarządza zwalnianiem pamięci. Interpreter wykonuje rzadko wywoływany kod bez kompilacji. Profiler śledzi hot-metody do kompilacji hybrydowej. Każdy moduł może działać niezależnie, co czyni ART elastycznym i skalowalnym.
Od Android 7.0 Nougat ART używa podejścia hybrydowego do kompilacji, łączącego zalety JIT i AOT. Podczas instalacji aplikacji ART nie wykonuje już pełnej kompilacji AOT — zamiast tego aplikacja uruchamia się w trybie interpretowanym z kompilacją JIT hot-metod. Skraca to czas instalacji i zajmowane miejsce.
Równolegle działa profiler tła (background profiler). Zbiera on statystyki wykonania: które metody są wywoływane najczęściej, które gałęzie kodu są wykonywane, które klasy są ładowane. Po zgromadzeniu wystarczającej ilości danych (zwykle po 2–3 uruchomieniach aplikacji) ART uruchamia dex2oat w tle i kompiluje tylko profilowane hot-metody do kodu natywnego.
ART obsługuje kilka trybów kompilacji zarządzanych przez system_server. Tryb "speed" kompiluje wszystkie metody do AOT (maksymalna wydajność, długa instalacja). Tryb "speed-profile" kompiluje tylko profilowane hot-metody (balans prędkości i rozmiaru). Tryb "verify" tylko weryfikuje kod bajtowy bez kompilacji (minimalne miejsce, interpretacja). Domyślnie używany jest speed-profile — optymalny dla większości aplikacji.
| Tryb | Kompilacja | Czas instalacji | Wydajność |
|---|---|---|---|
| speed | Pełna AOT | Długi | Maksymalna |
| speed-profile | Profilowana AOT | Szybki | Wysoka |
| verify | Bez kompilacji | Natychmiastowy | Interpretacja |
| space | Minimalna AOT | Średni | Średnia |
Profiler zbiera dane o wykonaniu do specjalnych plików .prof. Każda aplikacja przechowuje swój profil w /data/misc/profiles/. Po osiągnięciu progu (zwykle 1000 próbek) profiler uruchamia dex2oat w celu kompilacji zidentyfikowanych hot-metod. Profile są zachowywane między aktualizacjami aplikacji, co przyspiesza ponowną optymalizację po aktualizacjach OTA systemu.
Zarządzanie pamięcią w ART zostało radykalnie ulepszone w porównaniu z Dalvik. Zamiast jednowątkowego Concurrent Mark and Sweep (CMS) ART używa pokoleniowego modułu czyszczenia pamięci z kilkoma optymalizacjami: moving collector (zagęszczanie sterty), large object space (oddzielne przechowywanie dużych obiektów) i concurrent compaction (równoległe zagęszczanie).
Typowa pauza GC w ART wynosi 2–3 ms w porównaniu z 5–10 ms w Dalvik. Stało się to możliwe dzięki kilku mechanizmom. Po pierwsze, ART używa read-barrier zamiast stop-the-world dla faz concurrent. Po drugie, pokoleniowy moduł czyszczenia przetwarza tylko młode pokolenie obiektów w większości cykli, nie dotykając całej sterty. Po trzecie, large object space (LOS) jest alokowany oddzielnie i nie uczestniczy w zwykłych cyklach GC.
// Włączanie logów GC do debugowania
System.logV("ART", "GC trigger: allocation failed");
// Wymuszone wywołanie GC (niezalecane w produkcji)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Debug.getRuntimeIStats();
}
Pomimo ulepszonego GC, wycieki pamięci pozostają aktualnym problemem. Przyczyną specyficzną dla ART jest ładowanie bibliotek natywnych przez JNI bez prawidłowego zwalniania. Jeśli kod natywny alokuje pamięć przez malloc, ale nie wywołuje free, ART nie może zwolnić tej pamięci — znajduje się ona poza zarządzaną stertą. Narzędzie AddressSanitizer w Android NDK pomaga wykrywać takie wycieki.
ART i Dalvik to dwie zasadniczo różne implementacje tego samego zadania: uruchamianie aplikacji Android. Różnice dotyczą wszystkich poziomów: od kompilacji po zarządzanie pamięcią. Poniżej znajduje się porównanie kluczowych parametrów wydajności i kompatybilności.
Główna zaleta ART — eliminacja nagrzewania JIT. Na Dalvik aplikacja mogła zwalniać przez pierwsze 3–10 sekund, podczas gdy JIT kompilował hot-metody. Na ART wszystkie metody są już skompilowane do kodu natywnego (lub zostaną skompilowane w tle). Jest to szczególnie widoczne w grach i aplikacjach z ciężkim UI: różnica w fps może sięgać 15–20% na korzyść ART.
| Parametr | Dalvik | ART |
|---|---|---|
| Kompilacja | JIT (podczas działania) | AOT + hybrydowa (przy instalacji) |
| Czas uruchomienia | 3–10 s (nagrzewanie) | Natychmiastowy |
| Rozmiar APK | ~6–7 MB (DEX) | +20% (OAT) |
| Pauzy GC | 5–10 ms | 2–3 ms |
| Zużycie energii | Większe (JIT obciąża CPU) | Mniejsze (kod natywny) |
Wszystkie aplikacje napisane dla Dalvik działają na ART bez zmian. Google gwarantuje pełną wsteczną kompatybilność na poziomie kodu bajtowego DEX. Wyjątkiem jest kod używający Dalvik-specific internal API przez refleksję: elementy klas dalvik.system.DexFile oznaczone @hide w Android SDK. Taki kod należy zaktualizować do korzystania z publicznych API.
ART stało się pierwszym środowiskiem wykonawczym Android z natywną obsługą funkcji Java 8. Od Android 7.0 ART zawiera desugaryzację — proces przekształcania konstrukcji Java 8 (lambdy, method references, Stream API) w równoważny kod Java 7. Pozwala to używać nowoczesnej składni bez utraty kompatybilności ze starszymi urządzeniami.
Desugaryzacja jest wykonywana przez kompilator D8 i działa w następujący sposób. Kod źródłowy z lambdą jest przekształcany w syntetyczną metodę wewnątrz tej samej klasy, a lambda jest zastępowana wywołaniem invoke-custom. Środowisko ART obsługuje instrukcję invoke-custom dodaną specjalnie dla Java 8. Na urządzeniach z Android 6.0 i starszymi lambdy są desugaryzowane do klas anonimowych.
// Lambda Java 8 — desugaryzacja w ART
button.setOnClickListener(v -> handleClick(v));
// Po desugaryzacji (ekwiwalent w Java 7)
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
handleClick(v);
}
});
Nie wszystkie funkcje Java 8 są obsługiwane przez desugaryzację. API java.time (daty i czas) jest dostępne tylko przez desugar_jdk_libs — dodatkową bibliotekę dodawaną w build.gradle. Stream API również wymaga desugar_jdk_libs. java.util.function i Optional działają bez dodatkowych zależności. Pełna obsługa Java 8 jest dostępna na urządzeniach z Android 8.0 i nowszymi bez desugaryzacji.
Mimo że ART jest wstecznie kompatybilne, niektóre praktyki optymalizacyjne poprawiają wydajność właśnie w tym środowisku. Głównym zaleceniem jest minimalizowanie refleksji. ART kompiluje metody widoczne na etapie kompilacji do bezpośredniego wywołania kodu maszynowego. Refleksja zmusza ART do generowania dodatkowych stubów, co spowalnia wykonanie o 10–15%.
Od Android 9.0 w ART pojawiła się obsługa App Startup Optimization. Programista może oznaczyć klasy inicjalizacyjne w manifeście przez <initialization>, a ART wstępnie je załaduje podczas uruchamiania aplikacji. Skraca to czas uruchamiania o 5–15% dla aplikacji z dużą liczbą wtyczek lub bibliotek.
<!-- App Startup Optimization w AndroidManifest.xml -->
<application>
<profileable
android:shell="true"
android:enable="true" />
</application>
Do pomiaru wydajności na ART używaj systrace i perfetto. Systrace pokazuje czas kompilacji dex2oat, częstotliwość GC i szybkość renderowania klatek. Perfetto dostarcza bardziej szczegółowe informacje: rozkład wątków, czas przejść JNI, ładowanie bibliotek natywnych. Uruchomienie: adb shell perfetto -o /data/misc/perfetto-traces/trace.perfetto -t 10s sched freq idle am wm.
Często zadawane pytania
ART (Android Runtime) — to środowisko wykonawcze aplikacji Android, które kompiluje kod aplikacji do maszynowego podczas instalacji. Przyspiesza to uruchamianie i działanie aplikacji w porównaniu ze starym środowiskiem Dalvik.
ART kompiluje kod z wyprzedzeniem (AOT) podczas instalacji aplikacji, a Dalvik kompilował go fragmentami podczas działania (JIT). Dlatego na ART aplikacje uruchamiają się szybciej i zużywają mniej energii.
Wykonaj adb shell getprop i znajdź właściwość persist.sys.dalvik.vm.lib.2. Wartość "libart.so" oznacza ART, "libdvm.so" — Dalvik. Na wszystkich urządzeniach z Android 5.0+ środowiskiem wykonawczym jest ART.
Nieznacznie. Sama aplikacja pozostaje w formacie APK z plikami DEX. ART tworzy dodatkowy plik OAT w /data/dalvik-cache/, który zajmuje o 10–20% więcej miejsca niż oryginalny DEX, ale to przechowywanie nie wlicza się do rozmiaru APK.
Tak, ART obsługuje większość funkcji Java 8 poprzez mechanizm desugaryzacji. Lambdy, method references i interfejsy funkcyjne działają na wszystkich urządzeniach z Android 5.0+. Dla Stream API i java.time wymagana jest biblioteka desugar_jdk_libs.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również