Runtime — это программный слой, который управляет исполнением кода мобильного приложения: выделяет память, обрабатывает исключения, запускает garbage collection и диспетчеризует вызовы методов. Без runtime ни одно приложение не может выполняться — это прослойка между скомпилированным кодом и операционной системой. По данным Android Developer Documentation, 2025, среда выполнения — ключевой элемент платформы, определяющий производительность и совместимость.
Главное
Runtime (среда выполнения) — это инфраструктура, которая обеспечивает исполнение программы после её запуска. В контексте мобильной разработки runtime включает загрузчик классов, аллокатор памяти, garbage collector, диспетчер методов и обработчик исключений. Без этой прослойки операционная система не может исполнить байт-код Dalvik или Objective-C сообщения.
Мобильные платформы используют разные реализации runtime. Android применяет ART (Android Runtime) с гибридной AOT/JIT-компиляцией. iOS использует Objective-C Runtime — динамическую систему, основанную на message passing и SEL-идентификаторах. Оба подхода решают одну задачу: исполнить код разработчика на конкретном устройстве с максимальной производительностью.
По данным Google I/O 2024, Android Runtime обрабатывает более 10 миллиардов методов в сутки на устройствах по всему миру. Производительность runtime напрямую влияет на скорость запуска приложения, плавность анимаций и потребление батареи. Каждый вызов метода, каждое выделение памяти и каждый цикл garbage collection проходят через слой runtime.
Runtime system включает пять ключевых компонентов: загрузчик классов, менеджер памяти, интерпретатор или компилятор, диспетчер методов и систему безопасности. Каждый компонент выполняет строго определённую функцию в процессе исполнения кода.
Когда пользователь запускает приложение, ClassLoader загружает DEX-файлы (Android) или Mach-O бинарники (iOS) в оперативную память. В Android этот этап включает верификацию байт-кода: runtime проверяет, что код не содержит небезопасных инструкций, не выходит за границы массивов и соблюдает типы. Верификация — критический шаг безопасности, предотвращающий выполнение вредоносного кода.
Memory Manager выделяет и освобождает память под объекты. В Android ART используется concurrent garbage collector с поколенческой сборкой: молодые объекты проверяются чаще, старые — реже. Objective-C Runtime применяет Automatic Reference Counting (ARC), где компилятор вставляет вызовы retain/release автоматически.
Method dispatcher определяет, какая реализация метода будет вызвана. В статических языках (Kotlin, Swift) диспетчеризация выполняется через vtable — таблицу виртуальных методов. В динамических (Objective-C) сообщение проходит через objc_msgSend, который ищет реализацию в классе и его суперклассах. Результат кешируется в method cache для ускорения повторных вызовов.
Android Runtime (ART) — это виртуальная машина, исполняющая DEX-байт-код Android-приложений. ART заменил Dalvik в Android 5.0 Lollipop, предложив AOT-компиляцию: приложение компилируется в машинный код один раз во время установки. Это устранило накладные расходы на JIT-компиляцию при каждом запуске.
Начиная с Android 7.0 Nougat, ART использует гибридный подход. При установке выполняется JIT-компиляция только часто используемых методов (hot methods), остальной код интерпретируется. Фоновый процесс (profile-guided optimization) анализирует, какие методы вызываются чаще всего, и компилирует их AOT в простое устройства. Это сокращает время установки и одновременно обеспечивает высокую производительность.
ART также включает AOT compiler (dex2oat), который преобразует DEX-файлы в ELF-бинарники с машинным кодом ARM64. Компиляция выполняется с тремя уровнями оптимизации: quicken (быстрая), optimize (средняя) и everything (полная). По умолчанию Android применяет optimize, балансирующий между скоростью компиляции и производительностью кода.
class RuntimeExample {
fun measureExecutionTime() {
val start = System.nanoTime()
// Вызов метода, компилируемого ART
processData()
val end = System.nanoTime()
println("Время выполнения: ${end - start} нс")
}
}
В примере выше System.nanoTime() — нативный метод, вызов которого диспетчеризуется через ART runtime в ядро Linux. ART преобразует байт-код Kotlin в ARM64-инструкции, которые исполняются процессором устройства. Этот процесс происходит незаметно для разработчика, но его оптимизация — ключевая задача команды Android Platform.
Profile-guided optimization — механизм ART, собирающий профили использования методов. Файл profiles/
Разработчик может включить baseline profiles в своём Gradle-проекте. Это ручные аннотации, указывающие ART, какие методы компилировать AOT сразу после установки. Baseline profiles сокращают первый запуск на 40% без ожидания фонового профилирования.
Objective-C Runtime — это динамическая библиотека, обеспечивающая исполнение Objective-C кода на iOS и macOS. Её ядро — функция objc_msgSend, которая реализует message passing: вместо прямого вызова метода объект посылает сообщение с селектором, а runtime определяет, какая реализация должна выполниться.
Каждый объект Objective-C содержит указатель isa на класс, а класс — dispatch table (таблицу диспетчеризации), сопоставляющую селекторы (SEL) с реализациями (IMP). Когда вызывается метод, objc_msgSend проходит по цепочке: класс → суперкласс → NSObject, пока не найдёт IMP. Если реализация не найдена — runtime вызывает forwarding mechanism, который может перехватить сообщение или сгенерировать исключение.
Objective-C Runtime также поддерживает method swizzling — замену IMP у существующего селектора во время выполнения. Это мощный механизм, используемый в AOP-библиотеках и инструментах мониторинга, но требующий осторожности из-за влияния на всё приложение.
@interface RuntimeDemo : NSObject
- (void)printClassInfo;
@end
@implementation RuntimeDemo
- (void)printClassInfo {
// objc_getClass — функция runtime
Class cls = objc_getClass("RuntimeDemo");
unsigned int count;
Method *methods = class_copyMethodList(cls, &count);
NSLog("Количество методов: %d", count);
}
@end
Код демонстрирует прямое обращение к Objective-C Runtime API: objc_getClass получает объект класса по имени, class_copyMethodList извлекает список всех методов. Это reflection в действии — доступ к метаданным класса во время выполнения. Такой подход используется в XCTest для динамической регистрации тестов.
isa pointer — указатель на класс объекта, хранящийся в первых 8 байтах каждого объекта. Начиная с iOS 12, Apple внедрила isa-swizzling для оптимизации: младшие биты isa кодируют дополнительную информацию о состоянии объекта. Tagged pointers — ещё одна оптимизация, при которой значения до 60 бит (NSNumber, NSDate) хранятся непосредственно в указателе, без выделения объекта в куче. Это сокращает нагрузку на memory manager на 30%.
JIT (Just-In-Time) и AOT (Ahead-Of-Time) — два подхода к компиляции байт-кода в машинный. JIT компилирует код во время выполнения приложения, анализируя горячие участки и оптимизируя их на лету. AOT компилирует весь код заранее — при установке приложения или на стороне разработчика.
| Характеристика | JIT | AOT |
|---|---|---|
| Время компиляции | Во время выполнения | При установке / сборке |
| Размер APK/IPA | Меньше (только байт-код) | Больше (машинный код) |
| Скорость запуска | Ниже (необходима компиляция) | Выше (код готов к исполнению) |
| Оптимизация под устройство | Да (адаптивная) | Ограниченная (generic) |
| RAM потребление | Выше (компилятор в памяти) | Ниже |
Гибридный подход ART (Android 7+) считается оптимальным: приложение использует интерпретатор для редко вызываемых методов, JIT для hot-методов и AOT для методов из profile-guided optimization. iOS, напротив, использует строгий AOT через LLVM: Swift и Objective-C компилируются в машинный код на этапе сборки в Xcode.
По данным Apple Developer Documentation, 2024, Swift runtime добавляет около 15 МБ к размеру приложения. Flutter использует свою Dart VM, где JIT-компиляция работает в debug-режиме для hot reload, а AOT — в release-режиме для максимальной производительности. React Native использует Hermes — JavaScript engine с AOT-компиляцией, сокращающий время запуска на 50%.
ARM64 Runtime — это уровень, на котором машинный код взаимодействует с процессором устройства. Большинство современных мобильных устройств работают на ARM64 (aarch64) процессорах. Runtime транслирует байт-код или нативные вызовы в ARM64-инструкции, которые исполняет CPU.
Ключевые регистры ARM64, используемые runtime: x0–x7 (параметры функций), x8 (косвенный результат), x30 (адрес возврата), sp (stack pointer), fp (frame pointer). ART генерирует код, который соблюдает ARM64 Procedure Call Standard: все вызовы методов проходят через протокол, определённый архитектурой процессора.
Понимание ARM64 ABI важно при оптимизации производительности: inline-кэширование, предсказание ветвлений и выравнивание кода в памяти напрямую влияют на скорость работы runtime. Инструменты профилирования (Android Studio Profiler, Instruments) показывают, какие участки кода проводят больше всего времени в runtime — именно их оптимизация даёт наибольший прирост.
// Пример ARM64 assembly, генерируемого ART
// Вызов метода с двумя параметрами
mov x0, x23 // self (this)
mov x1, x24 // param1
mov x2, x25 // param2
bl methodEntryPoint // вызов через runtime
str x0, [sp, #8] // сохранение результата
В этом примере ARM64 инструкции mov передают аргументы в регистры x0–x2, bl вызывает entry point метода, а str сохраняет возвращаемое значение. Runtime генерирует такие инструкции для каждого вызова метода, оптимизируя последовательность через devirtualization и inlining.
Runtime overhead — неизбежная плата за динамическую диспетчеризацию. Каждый вызов метода через runtime требует: поиск реализации в dispatch table, проверку типов, вызов IMP и возврат результата. Измерения показывают, что runtime добавляет 10–50 нс на вызов в Objective-C и 5–20 нс в ART.
Для сокращения overhead разработчики используют monomorphic inlining (ART) и method caching (Objective-C). Kotlin/Native и Swift компилируются напрямую в ARM64, полностью устраняя runtime-прослойку, но теряя динамические возможности — рефлексию, swizzling, динамическую загрузку классов.
Часто задаваемые вопросы
SDK (Software Development Kit) — набор инструментов для разработки приложения (компилятор, библиотеки, утилиты). Runtime — среда, в которой уже разработанное приложение исполняется на устройстве. SDK нужен разработчику, runtime — пользователю.
Нет — runtime является частью операционной системы и не может быть заменён пользователем. ART встроен в Android Framework, Objective-C Runtime — в iOS. Разработчик может выбирать язык (Kotlin/Native без runtime) или использовать виртуальные машины вроде Dart VM во Flutter.
Да, runtime влияет на энергопотребление. Garbage collection в ART и Swift runtime используют CPU, что увеличивает расход заряда. Оптимизации вроде concurrent GC и tagged pointers в iOS снижают влияние runtime на батарею на 20–30%.
Runtime error — ошибка, возникающая во время выполнения: null pointer exception, index out of bounds, деление на ноль. В отличие от compile-time ошибок, они не обнаруживаются при сборке. Отлавливаются через try-catch блоки или crash reporting (Firebase Crashlytics, Sentry).
Swift runtime легче Objective-C: он не поддерживает dynamic dispatch по умолчанию, использует value types (struct) без выделения в куче и не имеет message forwarding. Swift методы вызываются напрямую через vtable, если не помечены @objc dynamic. Это даёт прирост скорости до 5x в бенчмарках.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также