Runtime to warstwa programowa, która zarządza wykonywaniem kodu aplikacji mobilnej: przydziela pamięć, obsługuje wyjątki, uruchamia garbage collection i dyspozytuje wywołania metod. Bez runtime żadna aplikacja nie może działać — to pośrednia warstwa między skompilowanym kodem a systemem operacyjnym. Według danych Android Developer Documentation, 2025 środowisko wykonawcze to kluczowy element platformy, który decyduje o wydajności i zgodności.
Najważniejsze
Runtime (środowisko wykonawcze) to infrastruktura, która zapewnia wykonywanie programu po jego uruchomieniu. W kontekście tworzenia aplikacji mobilnych runtime obejmuje ładowacz klas, alokator pamięci, garbage collector, dyspozytor metod i moduł obsługi wyjątków. Bez tej pośredniej warstwy system operacyjny nie może wykonać kodu bajtowego Dalvik ani komunikatów Objective-C.
Platformy mobilne używają różnych implementacji runtime. Android stosuje ART (Android Runtime) z hybrydową kompilacją AOT/JIT. iOS używa Objective-C Runtime — dynamicznego systemu opartego na message passing i identyfikatorach SEL. Oba podejścia rozwiązują to samo zadanie: wykonać kod programisty na konkretnym urządzeniu z maksymalną wydajnością.
Według danych Google I/O 2024 Android Runtime obsługuje ponad 10 miliardów wywołań metod dziennie na urządzeniach na całym świecie. Wydajność runtime bezpośrednio wpływa na szybkość uruchamiania aplikacji, płynność animacji i zużycie baterii. Każde wywołanie metody, każde przydzielenie pamięci i każdy cykl garbage collection przechodzą przez warstwę runtime.
Runtime system obejmuje pięć kluczowych komponentów: ładowacz klas, menedżer pamięci, interpreter lub kompilator, dyspozytor metod i system bezpieczeństwa. Każdy komponent wykonuje ściśle określoną funkcję w procesie wykonywania kodu.
Kiedy użytkownik uruchamia aplikację, ClassLoader ładuje pliki DEX (Android) lub binarne pliki Mach-O (iOS) do pamięci RAM. Na Androidzie ten etap obejmuje weryfikację kodu bajtowego: runtime sprawdza, czy kod nie zawiera niebezpiecznych instrukcji, nie wychodzi poza granice tablic i zachowuje typy. Weryfikacja to krytyczny krok bezpieczeństwa, który zapobiega wykonywaniu złośliwego kodu.
Memory Manager przydziela i zwalnia pamięć dla obiektów. W Androidzie ART używa concurrent garbage collector ze zbieraniem pokoleniowym: młode obiekty są sprawdzane częściej, stare — rzadziej. Objective-C Runtime stosuje Automatic Reference Counting (ARC), gdzie kompilator automatycznie wstawia wywołania retain/release.
Method dispatcher określa, która implementacja metody zostanie wywołana. W językach statycznych (Kotlin, Swift) dyspozycja odbywa się przez vtable — tablicę metod wirtualnych. W dynamicznych (Objective-C) komunikat przechodzi przez objc_msgSend, który szuka implementacji w klasie i jej superklasach. Wynik jest zapisywany w method cache, aby przyspieszyć powtarzające się wywołania.
Android Runtime (ART) to wirtualna maszyna, która wykonuje kod bajtowy DEX aplikacji Androida. ART zastąpił Dalvik w Androidzie 5.0 Lollipop, wprowadzając kompilację AOT: aplikacja jest kompilowana do kodu maszynowego jeden raz podczas instalacji. To wyeliminowało narzut kompilacji JIT przy każdym uruchomieniu.
Od Androida 7.0 Nougat ART stosuje podejście hybrydowe. Podczas instalacji wykonywana jest kompilacja JIT tylko często używanych metod (hot methods), a reszta kodu jest interpretowana. Proces w tle (profile-guided optimization) analizuje, które metody są wywoływane najczęściej, i kompiluje je AOT w okresach bezczynności urządzenia. To skraca czas instalacji i jednocześnie zapewnia wysoką wydajność.
ART zawiera również AOT compiler (dex2oat), który przekształca pliki DEX w binarne pliki ELF z kodem maszynowym ARM64. Kompilacja odbywa się z trzema poziomami optymalizacji: quicken (szybka), optimize (średnia) i everything (pełna). Domyślnie Android stosuje optimize, która równoważy szybkość kompilacji i wydajność kodu.
class RuntimeExample {
fun measureExecutionTime() {
val start = System.nanoTime()
// Wywołanie metody kompilowanej przez ART
processData()
val end = System.nanoTime()
println("Czas wykonania: ${end - start} ns")
}
}W powyższym przykładzie System.nanoTime() to metoda natywna, której wywołanie jest dyspozytowane przez ART runtime do jądra Linuxa. ART przekształca kod bajtowy Kotlin w instrukcje ARM64, które wykonuje procesor urządzenia. Ten proces odbywa się niezauważalnie dla programisty, ale jego optymalizacja to kluczowe zadanie zespołu Android Platform.
Optymalizacja na podstawie profili to mechanizm ART, który zbiera profile użycia metod. Plik profiles/
Programista może włączyć baseline profiles w swoim projekcie Gradle. To ręczne adnotacje, które wskazują ART, które metody kompilować AOT natychmiast po instalacji. Baseline profiles skracają pierwsze uruchomienie o 40% bez czekania na profilowanie w tle.
Objective-C Runtime to dynamiczna biblioteka, która zapewnia wykonywanie kodu Objective-C na iOS i macOS. Jej rdzeniem jest funkcja objc_msgSend, która implementuje message passing: zamiast bezpośredniego wywołania metody obiekt wysyła komunikat z selektorem, a runtime określa, która implementacja powinna zostać wykonana.
Każdy obiekt Objective-C zawiera wskaźnik isa do klasy, a klasa — dispatch table (tabelę dyspozycji), która odwzorowuje selektory (SEL) na implementacje (IMP). Kiedy wywoływana jest metoda, objc_msgSend przechodzi po łańcuchu: klasa → superklasa → NSObject, dopóki nie znajdzie IMP. Jeśli implementacja nie zostanie znaleziona, runtime wywołuje forwarding mechanism, który może przechwycić komunikat lub wygenerować wyjątek.
Objective-C Runtime obsługuje również method swizzling — zamianę IMP istniejącego selektora podczas wykonywania. To potężny mechanizm używany w bibliotekach AOP i narzędziach monitorowania, ale wymaga ostrożności ze względu na wpływ na całą aplikację.
@interface RuntimeDemo : NSObject
- (void)printClassInfo;
@end
@implementation RuntimeDemo
- (void)printClassInfo {
// objc_getClass — funkcja runtime
Class cls = objc_getClass("RuntimeDemo");
unsigned int count;
Method *methods = class_copyMethodList(cls, &count);
NSLog("Liczba metod: %d", count);
}
@endKod demonstruje bezpośredni dostęp do Objective-C Runtime API: objc_getClass pobiera obiekt klasy po nazwie, a class_copyMethodList wyodrębnia listę wszystkich metod. To działająca refleksja — dostęp do metadanych klasy podczas wykonywania. Takie podejście jest używane w XCTest do dynamicznej rejestracji testów.
isa pointer to wskaźnik do klasy obiektu, przechowywany w pierwszych 8 bajtach każdego obiektu. Od iOS 12 Apple wprowadziło isa-swizzling w celu optymalizacji: najmłodsze bity isa kodują dodatkowe informacje o stanie obiektu. Tagged pointers to kolejna optymalizacja, w której wartości do 60 bitów (NSNumber, NSDate) są przechowywane bezpośrednio we wskaźniku, bez przydzielania obiektu na stercie. To zmniejsza obciążenie menedżera pamięci o 30%.
JIT (Just-In-Time) i AOT (Ahead-Of-Time) to dwa podejścia do kompilacji kodu bajtowego do kodu maszynowego. JIT kompiluje kod podczas wykonywania aplikacji, analizując gorące fragmenty i optymalizując je na bieżąco. AOT kompiluje cały kod z wyprzedzeniem — podczas instalacji aplikacji lub po stronie programisty.
| Charakterystyka | JIT | AOT |
|---|---|---|
| Czas kompilacji | Podczas wykonywania | Przy instalacji / budowaniu |
| Rozmiar APK/IPA | Mniejszy (tylko kod bajtowy) | Większy (kod maszynowy) |
| Szybkość uruchamiania | Niższa (konieczna kompilacja) | Wyższa (kod gotowy do wykonania) |
| Optymalizacja pod urządzenie | Tak (adaptacyjna) | Ograniczona (generic) |
| Zużycie RAM | Większe (kompilator w pamięci) | Mniejsze |
Hybrydowe podejście ART (Android 7+) jest uważane za optymalne: aplikacja używa interpretera dla rzadko wywoływanych metod, JIT dla metod hot i AOT dla metod z profile-guided optimization. iOS z kolei używa ścisłego AOT przez LLVM: Swift i Objective-C są kompilowane do kodu maszynowego na etapie budowania w Xcode.
Według danych Apple Developer Documentation, 2024 Swift runtime dodaje około 15 MB do rozmiaru aplikacji. Flutter używa własnej Dart VM, gdzie kompilacja JIT działa w trybie debug dla hot reload, a AOT — w trybie release dla maksymalnej wydajności. React Native używa Hermes — silnika JavaScript z kompilacją AOT, który skraca czas uruchamiania o 50%.
ARM64 Runtime to poziom, na którym kod maszynowy współdziała z procesorem urządzenia. Większość nowoczesnych urządzeń mobilnych działa na procesorach ARM64 (aarch64). Runtime tłumaczy kod bajtowy lub wywołania natywne na instrukcje ARM64, które wykonuje CPU.
Kluczowe rejestry ARM64 używane przez runtime: x0–x7 (parametry funkcji), x8 (wynik pośredni), x30 (adres powrotu), sp (stack pointer), fp (frame pointer). ART generuje kod, który przestrzega ARM64 Procedure Call Standard: wszystkie wywołania metod przechodzą przez protokół zdefiniowany przez architekturę procesora.
Zrozumienie ARM64 ABI jest ważne przy optymalizacji wydajności: inline-caching, przewidywanie skoków i wyrównywanie kodu w pamięci bezpośrednio wpływają na szybkość działania runtime. Narzędzia profilowania (Android Studio Profiler, Instruments) pokazują, które fragmenty kodu spędzają najwięcej czasu w runtime — właśnie ich optymalizacja daje największy przyrost.
// Przykład asemblera ARM64 generowanego przez ART
// Wywołanie metody z dwoma parametrami
mov x0, x23 // self (this)
mov x1, x24 // param1
mov x2, x25 // param2
bl methodEntryPoint // wywołanie przez runtime
str x0, [sp, #8] // zapisanie wynikuW tym przykładzie instrukcje ARM64 mov przekazują argumenty do rejestrów x0–x2, bl wywołuje punkt wejścia metody, a str zapisuje wartość zwracaną. Runtime generuje takie instrukcje dla każdego wywołania metody, optymalizując sekwencję przez devirtualization i inlining.
Runtime overhead to nieunikniony koszt dynamicznej dyspozycji. Każde wywołanie metody przez runtime wymaga: znalezienia implementacji w dispatch table, sprawdzenia typów, wywołania IMP i zwrócenia wyniku. Pomiary pokazują, że runtime dodaje 10–50 ns na wywołanie w Objective-C i 5–20 ns w ART.
Aby zmniejszyć narzut, programiści używają monomorphic inlining (ART) i method caching (Objective-C). Kotlin/Native i Swift są kompilowane bezpośrednio do ARM64, całkowicie eliminując warstwę runtime, ale tracąc możliwości dynamiczne — refleksję, swizzling, dynamiczne ładowanie klas.
Często zadawane pytania
SDK (Software Development Kit) to zestaw narzędzi do tworzenia aplikacji (kompilator, biblioteki, narzędzia). Runtime to środowisko, w którym już opracowana aplikacja jest wykonywana na urządzeniu. SDK jest potrzebny programiście, runtime — użytkownikowi.
Nie — runtime jest częścią systemu operacyjnego i nie może zostać wymieniony przez użytkownika. ART jest wbudowany w Android Framework, a Objective-C Runtime — w iOS. Programista może wybrać język (Kotlin/Native bez runtime) lub użyć maszyn wirtualnych takich jak Dart VM we Flutterze.
Tak, runtime wpływa na zużycie energii. Garbage collection w ART i Swift runtime wykorzystują CPU, co zwiększa zużycie baterii. Optymalizacje takie jak concurrent GC i tagged pointers w iOS zmniejszają wpływ runtime na baterię o 20–30%.
Runtime error to błąd występujący podczas wykonywania: null pointer exception, index out of bounds, dzielenie przez zero. W przeciwieństwie do błędów kompilacji nie są one wykrywane podczas budowania. Wyłapuje się je przez bloki try-catch lub raportowanie awarii (Firebase Crashlytics, Sentry).
Swift runtime jest lżejszy niż Objective-C: nie obsługuje dynamic dispatch domyślnie, używa value types (struct) bez przydzielania na stercie i nie ma message forwarding. Metody Swift są wywoływane bezpośrednio przez vtable, jeśli nie są oznaczone @objc dynamic. Daje to przyrost szybkości do 5x w testach porównawczych.
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ż