Runtime est une couche logicielle qui gère l'exécution du code d'une application mobile : elle alloue la mémoire, traite les exceptions, lance le garbage collection et répartit les appels de méthodes. Sans runtime, aucune application ne peut s'exécuter — c'est la couche intermédiaire entre le code compilé et le système d'exploitation. Selon Android Developer Documentation, 2025, l'environnement d'exécution est un élément clé de la plateforme qui détermine les performances et la compatibilité.
Points clés
Runtime est l'infrastructure qui assure l'exécution du programme après son lancement. Dans le contexte du développement mobile, le runtime inclut le chargeur de classes, l'alloceur de mémoire, le ramasse-miettes, le répartiteur de méthodes et le gestionnaire d'exceptions. Sans cette couche intermédiaire, le système d'exploitation ne peut pas exécuter le bytecode Dalvik ni les messages Objective-C.
Les plateformes mobiles utilisent différentes implémentations de runtime. Android utilise ART (Android Runtime) avec compilation hybride AOT/JIT. iOS utilise Objective-C Runtime — un système dynamique basé sur le passage de messages et les identifiants SEL. Les deux approches résolvent le même problème : exécuter le code du développeur sur un appareil spécifique avec des performances maximales.
Selon Google I/O 2024, Android Runtime traite plus de 10 milliards de méthodes par jour sur les appareils du monde entier. Les performances du runtime affectent directement la vitesse de lancement de l'application, la fluidité des animations et la consommation de la batterie. Chaque appel de méthode, chaque allocation mémoire et chaque cycle de garbage collection passent par la couche runtime.
Runtime system comprend cinq composants clés : le chargeur de classes, le gestionnaire de mémoire, l'interpréteur ou compilateur, le répartiteur de méthodes et le système de sécurité. Chaque composant remplit une fonction strictement définie dans le processus d'exécution du code.
Lorsqu'un utilisateur lance une application, le ClassLoader charge les fichiers DEX (Android) ou les binaires Mach-O (iOS) dans la RAM. Sur Android, cette étape inclut la vérification du bytecode : le runtime vérifie que le code ne contient pas d'instructions dangereuses, ne dépasse pas les limites des tableaux et respecte les types. La vérification est une étape de sécurité critique qui empêche l'exécution de code malveillant.
Gestionnaire de mémoire alloue et libère la mémoire pour les objets. Dans Android ART, un ramasse-miettes concurrent avec collecte générationnelle est utilisé : les objets jeunes sont vérifiés plus souvent, les anciens moins souvent. Objective-C Runtime utilise l'Automatic Reference Counting (ARC), où le compilateur insère automatiquement les appels retain/release.
Répartiteur de méthodes détermine quelle implémentation de méthode sera appelée. Dans les langages statiques (Kotlin, Swift), la répartition s'effectue via vtable — une table de méthodes virtuelles. Dans les langages dynamiques (Objective-C), le message passe par objc_msgSend, qui cherche l'implémentation dans la classe et ses superclasses. Le résultat est mis en cache dans le method cache pour accélérer les appels répétés.
Android Runtime (ART) est une machine virtuelle qui exécute le bytecode DEX des applications Android. ART a remplacé Dalvik dans Android 5.0 Lollipop, introduisant la compilation AOT : l'application est compilée en code machine une fois lors de l'installation. Cela a éliminé la surcharge de la compilation JIT à chaque lancement.
À partir d'Android 7.0 Nougat, ART utilise une approche hybride. Lors de l'installation, la compilation JIT est effectuée uniquement pour les méthodes fréquemment utilisées (hot methods), le reste du code est interprété. Un processus en arrière-plan (profile-guided optimization) analyse quelles méthodes sont appelées le plus souvent et les compile AOT pendant les temps d'inactivité de l'appareil. Cela réduit le temps d'installation tout en garantissant des performances élevées.
ART inclut également un compilateur AOT (dex2oat) qui convertit les fichiers DEX en binaires ELF avec du code machine ARM64. La compilation est effectuée avec trois niveaux d'optimisation : quicken (rapide), optimize (moyen) et everything (complet). Par défaut, Android utilise optimize, équilibrant entre vitesse de compilation et performances du code.
class RuntimeExample {
fun measureExecutionTime() {
val start = System.nanoTime()
// Appel de méthode compilée par ART
processData()
val end = System.nanoTime()
println("Temps d'exécution : ${end - start} ns")
}
}
Dans l'exemple ci-dessus, System.nanoTime() est une méthode native dont l'appel est réparti via le runtime ART vers le noyau Linux. ART convertit le bytecode Kotlin en instructions ARM64 qui sont exécutées par le processeur de l'appareil. Ce processus se produit de manière transparente pour le développeur, mais son optimisation est une tâche clé de l'équipe Android Platform.
Profile-Guided Optimization est un mécanisme d'ART qui collecte des profils d'utilisation des méthodes. Le fichier profiles/
Le développeur peut activer les baseline profiles dans son projet Gradle. Ce sont des annotations manuelles qui indiquent à ART quelles méthodes compiler AOT immédiatement après l'installation. Les baseline profiles réduisent le premier lancement de 40 % sans attendre le profilage en arrière-plan.
Objective-C Runtime est une bibliothèque dynamique qui assure l'exécution du code Objective-C sur iOS et macOS. Son noyau est la fonction objc_msgSend, qui implémente le passage de messages : au lieu d'un appel direct de méthode, l'objet envoie un message avec un sélecteur, et le runtime détermine quelle implémentation doit s'exécuter.
Chaque objet Objective-C contient un pointeur isa vers sa classe, et la classe possède une dispatch table qui associe les sélecteurs (SEL) aux implémentations (IMP). Lorsqu'une méthode est appelée, objc_msgSend parcourt la chaîne : classe → superclasse → NSObject, jusqu'à trouver l'IMP. Si aucune implémentation n'est trouvée, le runtime invoque le forwarding mechanism, qui peut intercepter le message ou générer une exception.
Objective-C Runtime prend également en charge le method swizzling — le remplacement de l'IMP d'un sélecteur existant à l'exécution. C'est un mécanisme puissant utilisé dans les bibliothèques AOP et les outils de surveillance, mais qui nécessite de la prudence en raison de son impact sur l'ensemble de l'application.
@interface RuntimeDemo : NSObject
- (void)printClassInfo;
@end
@implementation RuntimeDemo
- (void)printClassInfo {
// objc_getClass — fonction runtime
Class cls = objc_getClass("RuntimeDemo");
unsigned int count;
Method *methods = class_copyMethodList(cls, &count);
NSLog("Nombre de méthodes : %d", count);
}
@end
Le code démontre un accès direct à l'API Objective-C Runtime : objc_getClass obtient l'objet classe par son nom, class_copyMethodList récupère la liste de toutes les méthodes. C'est la réflexion en action — l'accès aux métadonnées de classe à l'exécution. Cette approche est utilisée dans XCTest pour l'enregistrement dynamique des tests.
Pointeur isa est un pointeur vers la classe de l'objet, stocké dans les 8 premiers octets de chaque objet. À partir d'iOS 12, Apple a introduit l'isa-swizzling pour l'optimisation : les bits inférieurs d'isa encodent des informations supplémentaires sur l'état de l'objet. Les tagged pointers sont une autre optimisation où les valeurs jusqu'à 60 bits (NSNumber, NSDate) sont stockées directement dans le pointeur, sans allouer un objet sur le tas. Cela réduit la charge du gestionnaire de mémoire de 30 %.
JIT (Just-In-Time) et AOT (Ahead-Of-Time) sont deux approches pour compiler le bytecode en code machine. JIT compile le code pendant l'exécution de l'application, analysant les points chauds et les optimisant à la volée. AOT compile tout le code à l'avance — lors de l'installation de l'application ou du côté développeur.
| Caractéristique | JIT | AOT |
|---|---|---|
| Temps de compilation | Pendant l'exécution | Lors de l'installation/du build |
| Taille APK/IPA | Plus petite (bytecode uniquement) | Plus grande (code machine) |
| Vitesse de lancement | Plus faible (compilation nécessaire) | Plus élevée (code prêt) |
| Optimisation par appareil | Oui (adaptative) | Limitée (générique) |
| Consommation RAM | Plus élevée (compilateur en mémoire) | Plus faible |
L'approche hybride d'ART (Android 7+) est considérée comme optimale : l'application utilise un interpréteur pour les méthodes rarement appelées, JIT pour les méthodes hot et AOT pour les méthodes issues du profile-guided optimization. iOS, en revanche, utilise un AOT strict via LLVM : Swift et Objective-C sont compilés en code machine lors de l'étape de build dans Xcode.
Selon Apple Developer Documentation, 2024, le Swift runtime ajoute environ 15 Mo à la taille de l'application. Flutter utilise sa propre Dart VM, où la compilation JIT fonctionne en mode debug pour le hot reload, et AOT en mode release pour des performances maximales. React Native utilise Hermes — un moteur JavaScript avec compilation AOT qui réduit le temps de lancement de 50 %.
ARM64 Runtime est le niveau auquel le code machine interagit avec le processeur de l'appareil. La plupart des appareils mobiles modernes fonctionnent sur des processeurs ARM64 (aarch64). Le runtime traduit le bytecode ou les appels natifs en instructions ARM64 que le CPU exécute.
Registres ARM64 clés utilisés par le runtime : x0–x7 (paramètres de fonctions), x8 (résultat indirect), x30 (adresse de retour), sp (stack pointer), fp (frame pointer). ART génère du code qui suit l'ARM64 Procedure Call Standard : tous les appels de méthodes passent par le protocole défini par l'architecture du processeur.
Comprendre l'ABI ARM64 est important pour l'optimisation des performances : l'inline caching, la prédiction de branchement et l'alignement du code en mémoire affectent directement la vitesse du runtime. Les outils de profilage (Android Studio Profiler, Instruments) montrent quelles sections de code passent le plus de temps dans le runtime — leur optimisation apporte la plus grande amélioration.
// Exemple d'assembly ARM64 généré par ART
// Appel de méthode avec deux paramètres
mov x0, x23 // self (this)
mov x1, x24 // param1
mov x2, x25 // param2
bl methodEntryPoint // appel via runtime
str x0, [sp, #8] // sauvegarder le résultat
Dans cet exemple, les instructions ARM64 mov passent les arguments aux registres x0–x2, bl appelle le point d'entrée de la méthode, et str enregistre la valeur de retour. Le runtime génère de telles instructions pour chaque appel de méthode, optimisant la séquence via la dévirtualisation et l'inlining.
Runtime overhead est le coût inévitable de la répartition dynamique. Chaque appel de méthode via le runtime nécessite : la recherche de l'implémentation dans la dispatch table, la vérification de type, l'appel de l'IMP et le retour du résultat. Les mesures montrent que le runtime ajoute 10–50 ns par appel en Objective-C et 5–20 ns dans ART.
Pour réduire la surcharge, les développeurs utilisent l'inlining monomorphique (ART) et la mise en cache des méthodes (Objective-C). Kotlin/Native et Swift compilent directement en ARM64, éliminant complètement la couche runtime, mais perdant les capacités dynamiques — réflexion, swizzling, chargement dynamique de classes.
Questions fréquentes
SDK (Software Development Kit) est un ensemble d'outils pour le développement d'applications (compilateur, bibliothèques, utilitaires). Runtime est l'environnement dans lequel l'application déjà développée s'exécute sur l'appareil. Le développeur a besoin du SDK, l'utilisateur a besoin du runtime.
Non — le runtime fait partie du système d'exploitation et ne peut pas être remplacé par l'utilisateur. ART est intégré dans Android Framework, Objective-C Runtime dans iOS. Le développeur peut choisir le langage (Kotlin/Native sans runtime) ou utiliser des machines virtuelles comme Dart VM dans Flutter.
Oui, le runtime affecte la consommation d'énergie. Le garbage collection dans ART et Swift runtime utilisent le CPU, ce qui augmente la consommation de la batterie. Les optimisations comme le concurrent GC et les tagged pointers dans iOS réduisent l'impact du runtime sur la batterie de 20 à 30 %.
Runtime error est une erreur qui se produit pendant l'exécution : null pointer exception, index out of bounds, division par zéro. Contrairement aux erreurs de compilation, elles ne sont pas détectées lors du build. Elles sont détectées via des blocs try-catch ou un crash reporting (Firebase Crashlytics, Sentry).
Swift runtime est plus léger qu'Objective-C : il ne prend pas en charge le dispatch dynamique par défaut, utilise des value types (struct) sans allocation sur le tas et n'a pas de message forwarding. Les méthodes Swift sont appelées directement via vtable à moins d'être marquées @objc dynamic. Cela donne un gain de vitesse allant jusqu'à 5x dans les benchmarks.
Résumé
Nous développerons une application mobile clé en main
IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.
Lisez aussi