Runtime là một lớp phần mềm quản lý việc thực thi mã của ứng dụng di động: cấp phát bộ nhớ, xử lý ngoại lệ, chạy dọn rác (garbage collection) và điều phối các lời gọi phương thức. Nếu không có runtime, không ứng dụng nào có thể thực thi được — nó là lớp trung gian giữa mã đã biên dịch và hệ điều hành. Theo Android Developer Documentation, 2025, môi trường thực thi là một yếu tố then chốt của nền tảng, quyết định hiệu suất và khả năng tương thích.
Những điểm chính
Runtime là cơ sở hạ tầng đảm bảo việc thực thi chương trình sau khi nó được khởi chạy. Trong bối cảnh phát triển di động, runtime bao gồm trình tải lớp, trình cấp phát bộ nhớ, trình dọn rác, trình điều phối phương thức và trình xử lý ngoại lệ. Nếu không có lớp trung gian này, hệ điều hành không thể thực thi bytecode Dalvik hoặc thông điệp Objective-C.
Các nền tảng di động sử dụng các triển khai runtime khác nhau. Android sử dụng ART (Android Runtime) với biên dịch lai AOT/JIT. iOS sử dụng Objective-C Runtime — một hệ thống động dựa trên truyền thông điệp và định danh SEL. Cả hai phương pháp đều giải quyết cùng một vấn đề: thực thi mã của nhà phát triển trên một thiết bị cụ thể với hiệu suất tối đa.
Theo Google I/O 2024, Android Runtime xử lý hơn 10 tỷ phương thức mỗi ngày trên các thiết bị trên toàn thế giới. Hiệu suất runtime ảnh hưởng trực tiếp đến tốc độ khởi chạy ứng dụng, độ mượt của hoạt ảnh và mức tiêu thụ pin. Mỗi lời gọi phương thức, mỗi lần cấp phát bộ nhớ và mỗi chu kỳ dọn rác đều đi qua lớp runtime.
Hệ thống runtime bao gồm năm thành phần chính: trình tải lớp, trình quản lý bộ nhớ, trình thông dịch hoặc biên dịch, trình điều phối phương thức và hệ thống bảo mật. Mỗi thành phần thực hiện một chức năng được xác định chặt chẽ trong quá trình thực thi mã.
Khi người dùng khởi chạy ứng dụng, ClassLoader tải các tệp DEX (Android) hoặc tệp nhị phân Mach-O (iOS) vào RAM. Trong Android, giai đoạn này bao gồm xác minh bytecode: runtime kiểm tra rằng mã không chứa các lệnh không an toàn, không vượt quá giới hạn mảng và tuân thủ kiểu dữ liệu. Xác minh là một bước bảo mật quan trọng ngăn chặn việc thực thi mã độc.
Trình quản lý bộ nhớ cấp phát và giải phóng bộ nhớ cho các đối tượng. Trong Android ART, một trình dọn rác đồng thời với thu gom theo thế hệ được sử dụng: các đối tượng trẻ được kiểm tra thường xuyên hơn, các đối tượng cũ ít hơn. Objective-C Runtime sử dụng Automatic Reference Counting (ARC), nơi trình biên dịch tự động chèn các lời gọi retain/release.
Trình điều phối phương thức xác định việc triển khai phương thức nào sẽ được gọi. Trong các ngôn ngữ tĩnh (Kotlin, Swift), việc điều phối được thực hiện qua vtable — một bảng các phương thức ảo. Trong các ngôn ngữ động (Objective-C), thông điệp đi qua objc_msgSend, tìm kiếm việc triển khai trong lớp và các lớp cha của nó. Kết quả được lưu trong bộ đệm method cache để tăng tốc các lần gọi lặp lại.
Android Runtime (ART) là một máy ảo thực thi bytecode DEX của các ứng dụng Android. ART đã thay thế Dalvik trong Android 5.0 Lollipop, giới thiệu biên dịch AOT: ứng dụng được biên dịch thành mã máy một lần trong quá trình cài đặt. Điều này đã loại bỏ chi phí biên dịch JIT mỗi lần khởi chạy.
Bắt đầu từ Android 7.0 Nougat, ART sử dụng phương pháp lai. Trong quá trình cài đặt, biên dịch JIT chỉ được thực hiện cho các phương thức được sử dụng thường xuyên (hot methods), phần còn lại của mã được thông dịch. Một tiến trình nền (profile-guided optimization) phân tích phương thức nào được gọi thường xuyên nhất và biên dịch chúng AOT trong thời gian thiết bị rảnh. Điều này giảm thời gian cài đặt đồng thời đảm bảo hiệu suất cao.
ART cũng bao gồm một trình biên dịch AOT (dex2oat) chuyển đổi các tệp DEX thành tệp nhị phân ELF với mã máy ARM64. Biên dịch được thực hiện với ba mức tối ưu hóa: quicken (nhanh), optimize (trung bình) và everything (đầy đủ). Theo mặc định, Android sử dụng optimize, cân bằng giữa tốc độ biên dịch và hiệu suất mã.
class RuntimeExample {
fun measureExecutionTime() {
val start = System.nanoTime()
// Lời gọi phương thức được ART biên dịch
processData()
val end = System.nanoTime()
println("Thời gian thực thi: ${end - start} ns")
}
}
Trong ví dụ trên, System.nanoTime() là một phương thức gốc (native) có lời gọi được điều phối qua runtime ART vào nhân Linux. ART chuyển đổi bytecode Kotlin thành các lệnh ARM64 được thực thi bởi bộ xử lý của thiết bị. Quá trình này diễn ra trong suốt đối với nhà phát triển, nhưng việc tối ưu hóa nó là một nhiệm vụ then chốt của nhóm Android Platform.
Profile-guided optimization là một cơ chế của ART thu thập hồ sơ sử dụng phương thức. Tệp profiles/
Nhà phát triển có thể bật baseline profiles trong dự án Gradle của mình. Đây là các chú thích thủ công cho ART biết phương thức nào cần biên dịch AOT ngay sau khi cài đặt. Baseline profiles giảm lần khởi chạy đầu tiên xuống 40% mà không cần chờ tạo hồ sơ nền.
Objective-C Runtime là một thư viện động cung cấp khả năng thực thi mã Objective-C trên iOS và macOS. Cốt lõi của nó là hàm objc_msgSend, thực hiện truyền thông điệp: thay vì gọi phương thức trực tiếp, đối tượng gửi một thông điệp với bộ chọn (selector), và runtime xác định việc triển khai nào sẽ được thực thi.
Mỗi đối tượng Objective-C chứa một con trỏ isa trỏ đến lớp của nó, và lớp có một dispatch table ánh xạ các bộ chọn (SEL) đến các triển khai (IMP). Khi một phương thức được gọi, objc_msgSend duyệt qua chuỗi: lớp → lớp cha → NSObject, cho đến khi tìm thấy IMP. Nếu không tìm thấy triển khai nào, runtime gọi cơ chế chuyển tiếp (forwarding mechanism), có thể chặn thông điệp hoặc tạo ra một ngoại lệ.
Objective-C Runtime cũng hỗ trợ method swizzling — thay thế IMP của một bộ chọn hiện có tại thời điểm thực thi. Đây là một cơ chế mạnh mẽ được sử dụng trong các thư viện AOP và công cụ giám sát, nhưng đòi hỏi thận trọng do ảnh hưởng đến toàn bộ ứng dụng.
@interface RuntimeDemo : NSObject
- (void)printClassInfo;
@end
@implementation RuntimeDemo
- (void)printClassInfo {
// objc_getClass — hàm runtime
Class cls = objc_getClass("RuntimeDemo");
unsigned int count;
Method *methods = class_copyMethodList(cls, &count);
NSLog("Số lượng phương thức: %d", count);
}
@end
Mã này thể hiện quyền truy cập trực tiếp vào API Objective-C Runtime: objc_getClass lấy đối tượng lớp theo tên, class_copyMethodList lấy danh sách tất cả các phương thức. Đây là phản chiếu (reflection) trong hành động — truy cập siêu dữ liệu lớp tại thời điểm thực thi. Phương pháp này được sử dụng trong XCTest để đăng ký kiểm tra động.
Con trỏ isa là một con trỏ đến lớp của đối tượng, được lưu trữ trong 8 byte đầu tiên của mỗi đối tượng. Bắt đầu từ iOS 12, Apple đã giới thiệu isa-swizzling để tối ưu hóa: các bit thấp của isa mã hóa thông tin bổ sung về trạng thái của đối tượng. Tagged pointers là một tối ưu hóa khác, nơi các giá trị lên đến 60 bit (NSNumber, NSDate) được lưu trữ trực tiếp trong con trỏ, mà không cấp phát đối tượng trên heap. Điều này giảm tải cho trình quản lý bộ nhớ xuống 30%.
JIT (Just-In-Time) và AOT (Ahead-Of-Time) là hai phương pháp biên dịch bytecode thành mã máy. JIT biên dịch mã trong quá trình thực thi ứng dụng, phân tích các điểm nóng và tối ưu hóa chúng ngay lập tức. AOT biên dịch toàn bộ mã trước — trong quá trình cài đặt ứng dụng hoặc ở phía nhà phát triển.
| Đặc tính | JIT | AOT |
|---|---|---|
| Thời gian biên dịch | Trong khi thực thi | Khi cài đặt/xây dựng |
| Kích thước APK/IPA | Nhỏ hơn (chỉ bytecode) | Lớn hơn (mã máy) |
| Tốc độ khởi chạy | Thấp hơn (cần biên dịch) | Cao hơn (mã sẵn sàng) |
| Tối ưu hóa theo thiết bị | Có (thích ứng) | Hạn chế (chung) |
| Tiêu thụ RAM | Cao hơn (trình biên dịch trong bộ nhớ) | Thấp hơn |
Phương pháp lai của ART (Android 7+) được coi là tối ưu: ứng dụng sử dụng trình thông dịch cho các phương thức hiếm khi được gọi, JIT cho hot methods và AOT cho các phương thức từ profile-guided optimization. iOS, ngược lại, sử dụng AOT nghiêm ngặt qua LLVM: Swift và Objective-C được biên dịch thành mã máy ở giai đoạn xây dựng trong Xcode.
Theo Apple Developer Documentation, 2024, Swift runtime thêm khoảng 15 MB vào kích thước ứng dụng. Flutter sử dụng Dart VM của riêng mình, nơi biên dịch JIT hoạt động ở chế độ gỡ lỗi cho hot reload và AOT ở chế độ phát hành cho hiệu suất tối đa. React Native sử dụng Hermes — một công cụ JavaScript với biên dịch AOT giúp giảm thời gian khởi chạy xuống 50%.
ARM64 Runtime là cấp độ mà mã máy tương tác với bộ xử lý của thiết bị. Hầu hết các thiết bị di động hiện đại chạy trên bộ xử lý ARM64 (aarch64). Runtime dịch bytecode hoặc các lời gọi gốc thành các lệnh ARM64 mà CPU thực thi.
Các thanh ghi ARM64 chính được runtime sử dụng: x0–x7 (tham số hàm), x8 (kết quả gián tiếp), x30 (địa chỉ trả về), sp (con trỏ ngăn xếp), fp (con trỏ khung). ART tạo mã tuân theo ARM64 Procedure Call Standard: tất cả các lời gọi phương thức đều đi qua giao thức được xác định bởi kiến trúc bộ xử lý.
Hiểu ABI ARM64 rất quan trọng để tối ưu hóa hiệu suất: bộ nhớ đệm nội tuyến (inline caching), dự đoán rẽ nhánh (branch prediction) và căn chỉnh mã trong bộ nhớ ảnh hưởng trực tiếp đến tốc độ runtime. Các công cụ định hình (Android Studio Profiler, Instruments) cho thấy phần mã nào dành nhiều thời gian nhất trong runtime — tối ưu hóa chúng mang lại cải thiện lớn nhất.
// Ví dụ về hợp ngữ ARM64 do ART tạo ra
// Lời gọi phương thức với hai tham số
mov x0, x23 // self (this)
mov x1, x24 // param1
mov x2, x25 // param2
bl methodEntryPoint // gọi qua runtime
str x0, [sp, #8] // lưu kết quả
Trong ví dụ này, các lệnh ARM64 mov chuyển đối số vào các thanh ghi x0–x2, bl gọi điểm vào của phương thức, và str lưu giá trị trả về. Runtime tạo ra các lệnh như vậy cho mỗi lời gọi phương thức, tối ưu hóa trình tự thông qua devirtualization và inlining.
Chi phí runtime là cái giá không thể tránh khỏi của việc điều phối động. Mỗi lời gọi phương thức qua runtime yêu cầu: tìm kiếm triển khai trong dispatch table, kiểm tra kiểu, gọi IMP và trả về kết quả. Các phép đo cho thấy runtime thêm 10–50 ns mỗi lần gọi trong Objective-C và 5–20 ns trong ART.
Để giảm chi phí, các nhà phát triển sử dụng monomorphic inlining (ART) và method caching (Objective-C). Kotlin/Native và Swift biên dịch trực tiếp thành ARM64, loại bỏ hoàn toàn lớp runtime, nhưng mất đi các khả năng động — phản chiếu, swizzling, tải lớp động.
Các câu hỏi thường gặp
SDK (Software Development Kit) là một bộ công cụ để phát triển ứng dụng (trình biên dịch, thư viện, tiện ích). Runtime là môi trường mà ứng dụng đã phát triển chạy trên thiết bị. Nhà phát triển cần SDK, người dùng cần runtime.
Không — runtime là một phần của hệ điều hành và không thể bị thay thế bởi người dùng. ART được tích hợp trong Android Framework, Objective-C Runtime trong iOS. Nhà phát triển có thể chọn ngôn ngữ (Kotlin/Native không runtime) hoặc sử dụng máy ảo như Dart VM trong Flutter.
Có, runtime ảnh hưởng đến mức tiêu thụ năng lượng. Dọn rác trong ART và Swift runtime sử dụng CPU, làm tăng mức tiêu thụ pin. Các tối ưu hóa như concurrent GC và tagged pointers trong iOS giảm tác động của runtime lên pin xuống 20–30%.
Runtime error là lỗi xảy ra trong quá trình thực thi: null pointer exception, index out of bounds, chia cho số không. Không giống như lỗi biên dịch, chúng không được phát hiện trong quá trình xây dựng. Chúng được bắt qua khối try-catch hoặc báo cáo sự cố (Firebase Crashlytics, Sentry).
Swift runtime nhẹ hơn Objective-C: nó không hỗ trợ điều phối động theo mặc định, sử dụng value types (struct) mà không cấp phát trên heap và không có message forwarding. Các phương thức Swift được gọi trực tiếp qua vtable trừ khi được đánh dấu @objc dynamic. Điều này mang lại cải thiện tốc độ lên đến 5 lần trong các bài kiểm tra.
Tổng kết
Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay
IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.
Đọc thêm