Runtime в мобильной разработке: что это, runtime system и как работает

Автор: IT Sectr Опубликовано: 2026-05-17 Время чтения: 9 мин

Runtime — это программный слой, который управляет исполнением кода мобильного приложения: выделяет память, обрабатывает исключения, запускает garbage collection и диспетчеризует вызовы методов. Без runtime ни одно приложение не может выполняться — это прослойка между скомпилированным кодом и операционной системой. По данным Android Developer Documentation, 2025, среда выполнения — ключевой элемент платформы, определяющий производительность и совместимость.

Главное

  • Runtime — программная среда, исполняющая байт-код или машинный код мобильного приложения.
  • ART (Android Runtime) использует AOT-компиляцию и заменил Dalvik начиная с Android 5.0.
  • Objective-C Runtime обеспечивает динамическую диспетчеризацию методов и message passing в iOS.
  • JIT-компиляция компилирует байт-код в машинный непосредственно во время выполнения приложения.
  • ARM64 Runtime — аппаратный уровень, на котором исполняется оптимизированный код для 64-битных ARM-процессоров.

Что такое Runtime в мобильной разработке?

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: из каких компонентов состоит

Runtime system включает пять ключевых компонентов: загрузчик классов, менеджер памяти, интерпретатор или компилятор, диспетчер методов и систему безопасности. Каждый компонент выполняет строго определённую функцию в процессе исполнения кода.

Загрузчик классов и верификация

Когда пользователь запускает приложение, ClassLoader загружает DEX-файлы (Android) или Mach-O бинарники (iOS) в оперативную память. В Android этот этап включает верификацию байт-кода: runtime проверяет, что код не содержит небезопасных инструкций, не выходит за границы массивов и соблюдает типы. Верификация — критический шаг безопасности, предотвращающий выполнение вредоносного кода.

Менеджер памяти и Garbage Collector

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 для ускорения повторных вызовов.

Как работает ART на Android

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, балансирующий между скоростью компиляции и производительностью кода.

kotlin
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 (PGO)

Profile-guided optimization — механизм ART, собирающий профили использования методов. Файл profiles/.primary.prof содержит список hot-методов, которые компилируются AOT. По данным Android Performance Team, PGO ускоряет запуск приложения на 15–30% после нескольких дней использования, когда профиль накоплен.

Разработчик может включить baseline profiles в своём Gradle-проекте. Это ручные аннотации, указывающие ART, какие методы компилировать AOT сразу после установки. Baseline profiles сокращают первый запуск на 40% без ожидания фонового профилирования.

Как работает Objective-C Runtime на iOS

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-библиотеках и инструментах мониторинга, но требующий осторожности из-за влияния на всё приложение.

objective-c
@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 и tagged pointers

isa pointer — указатель на класс объекта, хранящийся в первых 8 байтах каждого объекта. Начиная с iOS 12, Apple внедрила isa-swizzling для оптимизации: младшие биты isa кодируют дополнительную информацию о состоянии объекта. Tagged pointers — ещё одна оптимизация, при которой значения до 60 бит (NSNumber, NSDate) хранятся непосредственно в указателе, без выделения объекта в куче. Это сокращает нагрузку на memory manager на 30%.

JIT и AOT-компиляция: сравнение подходов

JIT (Just-In-Time) и AOT (Ahead-Of-Time) — два подхода к компиляции байт-кода в машинный. JIT компилирует код во время выполнения приложения, анализируя горячие участки и оптимизируя их на лету. AOT компилирует весь код заранее — при установке приложения или на стороне разработчика.

ХарактеристикаJITAOT
Время компиляцииВо время выполненияПри установке / сборке
Размер 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 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 — именно их оптимизация даёт наибольший прирост.

cpp
// Пример 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 на производительность

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, динамическую загрузку классов.

Часто задаваемые вопросы

Чем отличается Runtime от SDK?

SDK (Software Development Kit) — набор инструментов для разработки приложения (компилятор, библиотеки, утилиты). Runtime — среда, в которой уже разработанное приложение исполняется на устройстве. SDK нужен разработчику, runtime — пользователю.

Можно ли заменить Runtime в мобильном приложении?

Нет — runtime является частью операционной системы и не может быть заменён пользователем. ART встроен в Android Framework, Objective-C Runtime — в iOS. Разработчик может выбирать язык (Kotlin/Native без runtime) или использовать виртуальные машины вроде Dart VM во Flutter.

Влияет ли Runtime на потребление батареи?

Да, runtime влияет на энергопотребление. Garbage collection в ART и Swift runtime используют CPU, что увеличивает расход заряда. Оптимизации вроде concurrent GC и tagged pointers в iOS снижают влияние runtime на батарею на 20–30%.

Что такое runtime error и как её отловить?

Runtime error — ошибка, возникающая во время выполнения: null pointer exception, index out of bounds, деление на ноль. В отличие от compile-time ошибок, они не обнаруживаются при сборке. Отлавливаются через try-catch блоки или crash reporting (Firebase Crashlytics, Sentry).

Как Swift runtime отличается от Objective-C Runtime?

Swift runtime легче Objective-C: он не поддерживает dynamic dispatch по умолчанию, использует value types (struct) без выделения в куче и не имеет message forwarding. Swift методы вызываются напрямую через vtable, если не помечены @objc dynamic. Это даёт прирост скорости до 5x в бенчмарках.

Итоги

  • Runtime — среда выполнения, управляющая памятью, методами и безопасностью кода.
  • ART (Android) использует гибрид JIT/AOT с profile-guided optimization для оптимальной производительности.
  • Objective-C Runtime построен на message passing через objc_msgSend и dispatch table.
  • JIT компилирует код на лету и адаптируется под устройство, AOT компилирует заранее для быстрого запуска.
  • ARM64 Runtime — аппаратный слой, исполняющий машинный код на современных процессорах.
  • Runtime overhead составляет 5–50 нс на вызов метода и минимизируется inlining и кешированием.
  • Понимание runtime необходимо для оптимизации производительности, отладки и выбора архитектуры приложения.

Мы разработаем мобильное приложение под ключ

IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

Читайте также