Runtime είναι ένα επίπεδο λογισμικού που διαχειρίζεται την εκτέλεση του κώδικα μιας εφαρμογής για κινητά: κατανέμει μνήμη, διαχειρίζεται εξαιρέσεις, εκκινεί το garbage collection και διανέμει τις κλήσεις μεθόδων. Χωρίς runtime καμία εφαρμογή δεν μπορεί να εκτελεστεί — είναι το ενδιάμεσο επίπεδο μεταξύ του μεταγλωττισμένου κώδικα και του λειτουργικού συστήματος. Σύμφωνα με Android Developer Documentation, 2025, το περιβάλλον εκτέλεσης είναι το βασικό στοιχείο της πλατφόρμας που καθορίζει την απόδοση και τη συμβατότητα.
Τα βασικά
Runtime (περιβάλλον εκτέλεσης) είναι η υποδομή που εξασφαλίζει την εκτέλεση ενός προγράμματος μετά την εκκίνησή του. Στο πλαίσιο της ανάπτυξης εφαρμογών για κινητά, το runtime περιλαμβάνει τον φορτωτή κλάσεων, τον κατανεμητή μνήμης, το garbage collector, τον διανομέα μεθόδων και τον χειριστή εξαιρέσεων. Χωρίς αυτό το ενδιάμεσο επίπεδο, το λειτουργικό σύστημα δεν μπορεί να εκτελέσει το bytecode 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 περιλαμβάνει πέντε βασικά στοιχεία: φορτωτή κλάσεων, διαχειριστή μνήμης, διερμηνέα ή μεταγλωττιστή, διανομέα μεθόδων και σύστημα ασφαλείας. Κάθε στοιχείο επιτελεί μια αυστηρά καθορισμένη λειτουργία στη διαδικασία εκτέλεσης κώδικα.
Όταν ο χρήστης εκκινεί την εφαρμογή, ο ClassLoader φορτώνει τα αρχεία DEX (Android) ή τα δυαδικά Mach-O (iOS) στη μνήμη εργασίας. Στο Android, αυτό το στάδιο περιλαμβάνει την επαλήθευση του bytecode: το runtime ελέγχει ότι ο κώδικας δεν περιέχει επικίνδυνες εντολές, δεν υπερβαίνει τα όρια των πινάκων και τηρεί τους τύπους. Η επαλήθευση είναι ένα κρίσιμο βήμα ασφαλείας που αποτρέπει την εκτέλεση κακόβουλου κώδικα.
Ο Memory Manager κατανέμει και απελευθερώνει μνήμη για τα αντικείμενα. Στο Android, το ART χρησιμοποιεί ταυτόχρονο 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) είναι μια εικονική μηχανή που εκτελεί το bytecode 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} ns")
}
}Στο παραπάνω παράδειγμα, το System.nanoTime() είναι μια εγγενής μέθοδος της οποίας η κλήση διανέμεται μέσω του ART runtime στον πυρήνα Linux. Το ART μετατρέπει το bytecode Kotlin σε εντολές ARM64, τις οποίες εκτελεί ο επεξεργαστής της συσκευής. Αυτή η διαδικασία γίνεται απαρατήρητα για τον προγραμματιστή, αλλά η βελτιστοποίησή της είναι βασικό καθήκον της ομάδας Android Platform.
Η βελτιστοποίηση που βασίζεται σε προφίλ είναι ένας μηχανισμός ART που συλλέγει προφίλ χρήσης μεθόδων. Το αρχείο profiles/
Ο προγραμματιστής μπορεί να ενεργοποιήσει τα baseline profiles στο έργο του Gradle. Πρόκειται για χειροκίνητους σχολιασμούς που υποδεικνύουν στο ART ποιες μεθόδους να μεταγλωττίσει AOT αμέσως μετά την εγκατάσταση. Τα baseline profiles μειώνουν την πρώτη εκκίνηση κατά 40% χωρίς να περιμένουν την προφιλοποίηση παρασκηνίου.
Objective-C Runtime είναι μια δυναμική βιβλιοθήκη που εξασφαλίζει την εκτέλεση κώδικα Objective-C σε iOS και macOS. Ο πυρήνας της είναι η συνάρτηση objc_msgSend, η οποία υλοποιεί το message passing: αντί για άμεση κλήση μεθόδου, το αντικείμενο στέλνει ένα μήνυμα με selector, και το runtime καθορίζει ποια υλοποίηση πρέπει να εκτελεστεί.
Κάθε αντικείμενο Objective-C περιέχει έναν δείκτη isa στην κλάση, και η κλάση έχει έναν dispatch table (πίνακα διανομής) που αντιστοιχίζει τους selectors (SEL) σε υλοποιήσεις (IMP). Όταν καλείται μια μέθοδος, το objc_msgSend διασχίζει την αλυσίδα: κλάση → υπερκλάση → NSObject, μέχρι να βρει IMP. Αν η υλοποίηση δεν βρεθεί, το runtime καλεί τον μηχανισμό forwarding, ο οποίος μπορεί να αναχαιτίσει το μήνυμα ή να δημιουργήσει εξαίρεση.
Το Objective-C Runtime υποστηρίζει επίσης το method swizzling — την αντικατάσταση του IMP ενός υπάρχοντος selector κατά την εκτέλεση. Είναι ένας ισχυρός μηχανισμός που χρησιμοποιείται σε βιβλιοθήκες 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 bytes κάθε αντικειμένου. Από το iOS 12, η Apple εισήγαγε το isa-swizzling για βελτιστοποίηση: τα κατώτερα bits του isa κωδικοποιούν πρόσθετες πληροφορίες για την κατάσταση του αντικειμένου. Οι tagged pointers είναι μια άλλη βελτιστοποίηση, όπου τιμές έως 60 bit (NSNumber, NSDate) αποθηκεύονται απευθείας στον δείκτη, χωρίς κατανομή αντικειμένου στο heap. Αυτό μειώνει το φορτίο του διαχειριστή μνήμης κατά 30%.
JIT (Just-In-Time) και AOT (Ahead-Of-Time) είναι δύο προσεγγίσεις για τη μεταγλώττιση bytecode σε κώδικα μηχανής. Το JIT μεταγλωττίζει τον κώδικα κατά την εκτέλεση της εφαρμογής, αναλύοντας τα καυτά σημεία και βελτιστοποιώντας τα εν κινήσει. Το AOT μεταγλωττίζει ολόκληρο τον κώδικα εκ των προτέρων — κατά την εγκατάσταση της εφαρμογής ή από την πλευρά του προγραμματιστή.
| Χαρακτηριστικό | JIT | AOT |
|---|---|---|
| Χρόνος μεταγλώττισης | Κατά την εκτέλεση | Κατά την εγκατάσταση / δημιουργία |
| Μέγεθος APK/IPA | Μικρότερο (μόνο bytecode) | Μεγαλύτερο (κώδικας μηχανής) |
| Ταχύτητα εκκίνησης | Χαμηλότερη (απαιτείται μεταγλώττιση) | Υψηλότερη (κώδικας έτοιμος για εκτέλεση) |
| Βελτιστοποίηση για τη συσκευή | Ναι (προσαρμοστική) | Περιορισμένη (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 MB στο μέγεθος της εφαρμογής. Το Flutter χρησιμοποιεί τη δική του Dart VM, όπου η μεταγλώττιση JIT λειτουργεί σε λειτουργία debug για hot reload, και το AOT — σε λειτουργία release για μέγιστη απόδοση. Το React Native χρησιμοποιεί το Hermes — μια μηχανή JavaScript με μεταγλώττιση AOT που μειώνει τον χρόνο εκκίνησης κατά 50%.
ARM64 Runtime είναι το επίπεδο στο οποίο ο κώδικας μηχανής αλληλεπιδρά με τον επεξεργαστή της συσκευής. Οι περισσότερες σύγχρονες συσκευές για κινητά λειτουργούν σε επεξεργαστές ARM64 (aarch64). Το runtime μεταφράζει το bytecode ή τις εγγενείς κλήσεις σε εντολές ARM64, τις οποίες εκτελεί η CPU.
Οι βασικοί καταχωρητές ARM64 που χρησιμοποιεί το runtime: x0–x7 (παράμετροι συναρτήσεων), x8 (έμμεσο αποτέλεσμα), x30 (διεύθυνση επιστροφής), sp (stack pointer), fp (frame pointer). Το ART παράγει κώδικα που τηρεί το ARM64 Procedure Call Standard: όλες οι κλήσεις μεθόδων περνούν από το πρωτόκολλο που ορίζει η αρχιτεκτονική του επεξεργαστή.
Η κατανόηση του ARM64 ABI είναι σημαντική στη βελτιστοποίηση της απόδοσης: η ενσωματωμένη προσωρινή μνήμη, η πρόβλεψη διακλαδώσεων και η στοίχιση του κώδικα στη μνήμη επηρεάζουν άμεσα την ταχύτητα λειτουργίας του 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 καλεί το σημείο εισόδου της μεθόδου, και το str αποθηκεύει την τιμή επιστροφής. Το runtime παράγει τέτοιες εντολές για κάθε κλήση μεθόδου, βελτιστοποιώντας την ακολουθία μέσω devirtualization και inlining.
Runtime overhead είναι το αναπόφευκτο κόστος της δυναμικής διανομής. Κάθε κλήση μεθόδου μέσω του runtime απαιτεί: αναζήτηση της υλοποίησης στον dispatch table, έλεγχο τύπων, κλήση του IMP και επιστροφή του αποτελέσματος. Οι μετρήσεις δείχνουν ότι το runtime προσθέτει 10–50 ns ανά κλήση στο Objective-C και 5–20 ns στο ART.
Για τη μείωση της επιβάρυνσης, οι προγραμματιστές χρησιμοποιούν monomorphic inlining (ART) και method caching (Objective-C). Το Kotlin/Native και η Swift μεταγλωττίζονται απευθείας σε ARM64, εξαλείφοντας εντελώς το επίπεδο runtime, αλλά χάνοντας τις δυναμικές δυνατότητες — το reflection, το 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, διαίρεση με το μηδέν. Σε αντίθεση με τα σφάλματα μεταγλώττισης, αυτά δεν ανιχνεύονται κατά τη δημιουργία. Πιάνονται μέσω μπλοκ try-catch ή αναφορών σφαλμάτων (Firebase Crashlytics, Sentry).
Swift runtime είναι ελαφρύτερο από το Objective-C: δεν υποστηρίζει dynamic dispatch από προεπιλογή, χρησιμοποιεί value types (struct) χωρίς κατανομή στο heap και δεν έχει message forwarding. Οι μέθοδοι Swift καλούνται απευθείας μέσω vtable, αν δεν επισημαίνονται με @objc dynamic. Αυτό δίνει αύξηση ταχύτητας έως 5 φορές στα benchmark.
Συμπεράσματα
Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση
Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης