Cold Start — khởi động nguội và tối ưu trong Android

Tác giả: IT Sectr Đã đăng: 2026-03-31 Thời gian đọc: 9 phút

Cold Start là chu trình khởi động hoàn chỉnh của một ứng dụng Android bắt đầu từ trạng thái không, khi tiến trình ứng dụng không tồn tại trong bộ nhớ và Activity chưa được tạo. Hệ thống tạo một tiến trình mới, tải các lớp, khởi tạo Application, tạo Activity và thực hiện vẽ đầu tiên. Theo Google, 2024, khởi động nguội trên thiết bị tầm trung có thể mất từ 1 đến 5 giây và cứ mỗi 100 ms trì hoãn làm giảm 3% khả năng giữ chân người dùng.

Những điểm chính

  • Cold Start — khởi động ứng dụng Android từ đầu: tiến trình mới, tải lớp, khởi tạo
  • Chỉ số được đo từ khi bắt đầu tiến trình đến lần vẽ đầu tiên (TTID hoặc TTFD)
  • Các giai đoạn khởi động: tạo tiến trình → Application.onCreate → Activity.onCreate → khung hình đầu tiên
  • Tối ưu bao gồm khởi tạo trễ, Baseline Profiles và giảm kích thước DEX
  • Google Play sử dụng Cold Start là một trong những chỉ số chính trong Android Vitals

Cold Start là gì

Cold Start (khởi động nguội) là một kịch bản trong đó ứng dụng Android được khởi động từ trạng thái ban đầu nhất: hệ điều hành tạo một tiến trình mới (fork từ Zygote), cấp phát bộ nhớ, tải mã DEX vào ART, khởi tạo các lớp và tạo một phiên bản Application, sau đó là Activity đầu tiên. Trước khi khởi động ứng dụng, không có dữ liệu về nó trong bộ nhớ thiết bị, ngoại trừ các hình ảnh lớp được lưu trong bộ nhớ đệm nếu Background Dexopt được sử dụng.

Khi nào Cold Start xảy ra

Khởi động nguội xảy ra trong ba trường hợp: khi khởi động lần đầu sau khi cài đặt ứng dụng, khi khởi động sau khi khởi động lại thiết bị và khi khởi động sau khi hệ thống đã xóa tiến trình do thiếu bộ nhớ. Trên các thiết bị có 2–4 GB RAM, hệ thống xóa các tiến trình nền khá mạnh mẽ, do đó Cold Start có thể xảy ra mỗi khi người dùng quay lại ứng dụng sau vài giờ không hoạt động. Trên Android 12+, hệ thống có thể giữ một tiến trình bị đóng băng (freeze / cached), nhưng với chế độ tiết kiệm bộ nhớ hoạt động (OOM-killer), tiến trình sẽ bị kết thúc.

Tại sao Cold Start là chỉ số quan trọng

Theo Google (báo cáo Find My Device, 2023), 65% người dùng đóng ứng dụng nếu nó không mở trong vòng 3 giây. Đối với mạng xã hội và tin nhắn, nơi người dùng quay lại hàng chục lần mỗi ngày, Cold Start ảnh hưởng trực tiếp đến khả năng giữ chân. Trong Google Play Console, chỉ số Cold Start là một phần của phần Android Vitals và được hiển thị như một trong các chỉ số ANR và hiệu suất. Ứng dụng vượt quá ngưỡng Cold Start “xấu” (hơn 5 giây trên 25% thiết bị) sẽ nhận được cảnh báo trong bảng điều khiển và có thể bị giảm hạng trong kết quả tìm kiếm.

Cold Start vs Warm Start vs Hot Start

Android phân biệt ba loại khởi động ứng dụng, mỗi loại có thời lượng, tác động đến UX và cách tiếp cận tối ưu khác nhau. Hiểu sự khác biệt là cần thiết để chọn chiến lược phân tích đúng đắn.

Loại khởi độngTrạng thái tiến trìnhApplication.onCreateThời gian điển hình
ColdKhông có tiến trìnhĐược thực thi1–5 giây
WarmCó tiến trình, không có ActivityKhông thực thi200–600 ms
HotTiến trình + Activity trong bộ nhớKhông thực thi< 200 ms

Warm Start xảy ra khi tiến trình ứng dụng đã tồn tại trong nền, nhưng Activity đã bị hủy (ví dụ: người dùng quay lại sau một thời gian dài và hệ thống đã giải phóng bộ nhớ Activity). Hot Start — khi người dùng thu nhỏ ứng dụng và mở lại ngay lập tức: Activity bị tạm dừng và việc khôi phục mất thời gian tối thiểu. Đối với người dùng, Cold Start là loại khởi động dễ nhận thấy nhất và việc tối ưu nó mang lại cải thiện lớn nhất về UX.

Chuyển đổi giữa các loại

Cold Start có thể trở thành Warm Start sau khi ứng dụng đã được khởi động ít nhất một lần — ART lưu vào bộ nhớ đệm các hình ảnh lớp đã biên dịch (Image trong Boot Profile) và việc tải DEX tiếp theo nhanh hơn. Do đó, lần khởi động thứ hai sau Cold Start đầu tiên thường nhanh hơn 20–40%. Nếu ứng dụng sử dụng Baseline Profiles, các hồ sơ được tải trong lần khởi động đầu tiên và lần khởi động thứ hai có thể nhanh hơn nữa: Google Play, đã phát hành Baseline Profiles, đã tăng tốc Cold Start lên 30% trên các thiết bị có Android 12+.

Các giai đoạn khởi động nguội

Cold Start bao gồm các giai đoạn được xác định chặt chẽ, mỗi giai đoạn có thể được đo và tối ưu độc lập. Biết các giai đoạn giúp xác định ứng dụng đang mất thời gian ở giai đoạn nào. Google xác định bốn giai đoạn chính: tạo tiến trình, khởi tạo Application, tạo Activity và khung hình đầu tiên.

Giai đoạn 1: Tạo tiến trình (fork)

Hệ thống Android (ActivityManagerService) tạo một tiến trình mới bằng cách fork từ tiến trình Zygote. Zygote là một tiến trình được tải sẵn với các lớp Android chung. Fork mất 30–80 ms — thời gian này nằm ngoài tầm kiểm soát của ứng dụng. Sau fork, ActivityThread được khởi động — phiên bản vòng lặp chính của ứng dụng. Ở giai đoạn này, tải lớp cũng diễn ra thông qua ClassLoader và ART bắt đầu giải thích bytecode đầu tiên. Nếu ứng dụng sử dụng nhiều bộ khởi tạo tĩnh, giai đoạn này có thể kéo dài.

Giai đoạn 2: Application.onCreate

Ngay sau khi ActivityThread khởi động, Application.onCreate được gọi. Đây là nơi các nhà phát triển thường mắc lỗi nhất, khởi tạo mọi thứ cùng một lúc: Crashlytics, Firebase, máy khách mạng, cơ sở dữ liệu, thành phần Dagger, vùng chứa DI. Mỗi lần khởi tạo như vậy là thời gian bị chặn trên luồng chính. Nếu Application.onCreate mất 500 ms, người dùng sẽ thấy màn hình trắng (hoặc đen) trong nửa giây. Thời lượng tối ưu của giai đoạn này là dưới 200 ms trên thiết bị tầm trung.

Giai đoạn 3: Activity.onCreate

Sau khi khởi tạo Application, một phiên bản Activity được tạo (MainActivity hoặc Launcher Activity). Activity.onCreate được gọi, nơi diễn ra setContentView, khởi tạo fragment, thiết lập ViewModel và đăng ký LiveData/Flow. Nếu onCreate tải dữ liệu (SharedPreferences, SQLite, API) đồng bộ trên luồng chính, giai đoạn sẽ kéo dài. Mục tiêu là giữ onCreate trong khoảng 200–400 ms trên thiết bị tầm trung.

Giai đoạn 4: Khung hình đầu tiên (TTFD)

Sau khi onCreate hoàn tất, quá trình kết xuất đầu tiên bắt đầu: đo, bố cục, vẽ. Khoảnh khắc này được gọi là TTFD (Time To First Draw). Nếu ứng dụng sử dụng màn hình splash (qua SplashScreen API trên Android 12+ hoặc qua theme), việc kết xuất có thể diễn ra nhanh hơn nhưng người dùng vẫn sẽ đợi cho đến khi splash biến mất. TTFD lý tưởng cho Cold Start là dưới 1,5 giây.

Cách đo Cold Start

Đo Cold Start yêu cầu các công cụ đặc biệt, vì ghi nhật ký thông thường (Log.d) chỉ bắt đầu hoạt động sau khi tạo Application và thời gian fork cũng như tải lớp vẫn không thể truy cập được. Google khuyến nghị ba phương pháp: lệnh ADB, Android Vitals và macro hiệu suất tùy chỉnh.

Đo qua ADB

Phương pháp đơn giản và có thể tái tạo nhất là lệnh adb shell am start -S -W. Cờ -S buộc dừng ứng dụng trước khi khởi động (đảm bảo Cold Start). Lệnh xuất ra ba chỉ số: ThisTime (thời gian bắt đầu Activity), TotalTime (tổng thời gian bao gồm khởi động tiến trình) và WaitTime (thời gian bao gồm tất cả độ trễ của Activity Manager). Để có phép đo sạch, hãy thực hiện 5–7 lần đo và sử dụng trung vị — các lần đo đơn lẻ chịu ảnh hưởng của nhiễu (CPU throttling, tải nền).

bash
# Cold Start cưỡng bức với đo lường
$ adb shell am start -S -W \
    com.example.app/.MainActivity

# Đầu ra lệnh:
# ThisTime: 1842 ms
# TotalTime: 1842 ms
# WaitTime: 1855 ms

Android Vitals (Google Play Console)

Google Play Console thu thập các chỉ số ẩn danh từ tất cả các thiết bị đã cài đặt ứng dụng. Trong phần Android Vitals → Launch time, phân phối trung vị của Cold Start theo mẫu thiết bị và phiên bản Android được hiển thị. Đây là cách duy nhất để thấy các chỉ số thực tế trên thiết bị của người dùng, không chỉ trên thiết bị thử nghiệm. Nếu Cold Start vượt quá 5 giây trên Redmi 9A (2 GB RAM) và 1,2 giây trên Pixel 8, vấn đề là kích thước bộ nhớ và số lượng lớp. Google cũng hiển thị độ trễ người dùng cảm nhận được dựa trên phân vị thứ 25.

Macrobenchmark

Google Jetpack Macrobenchmark (thư viện androidx.benchmark) cho phép viết các bài kiểm tra khởi động ứng dụng có công cụ. Bài kiểm tra cài đặt ứng dụng, khởi động nó từ trạng thái nguội và đo thời gian cho đến khung hình đầu tiên. Macrobenchmark tự động chạy 20 lần, loại bỏ các giá trị ngoại lệ và hiển thị các phân vị ổn định. Đối với CI/CD, bạn có thể so sánh đường cơ sở và lần khởi động hiện tại — nếu thời gian tăng, đường ống CI có thể thất bại.

Cách tối ưu Cold Start

Tối ưu Cold Start là công việc có hệ thống ảnh hưởng đến nhiều cấp độ của ứng dụng: mã, tài nguyên, cấu hình xây dựng và kiến trúc khởi tạo. Google khuyến nghị bắt đầu với phần đắt nhất — Application.onCreate — và tiến dần đến các chi tiết nhỏ hơn.

Khởi tạo trễ (Lazy Init)

Di chuyển tất cả các khởi tạo không cần thiết khi khởi động ra khỏi Application.onCreate đến điểm sử dụng đầu tiên. Firebase, Crashlytics, SDK phân tích, thông báo đẩy, thành phần DI — tất cả có thể được khởi tạo sau khi màn hình đầu tiên được kết xuất. Sử dụng Lazy (by lazy) trong Kotlin hoặc khởi tạo ContentProvider với lệnh gọi initialize(context) rõ ràng. Theo Google (Android Performance, 2023), khởi tạo trễ giảm Cold Start 40–60% cho các ứng dụng sử dụng 5+ SDK.

Baseline Profiles

Baseline Profiles là biên dịch AOT của các lớp và phương thức quan trọng được sử dụng khi khởi động ứng dụng. Nếu không có Baseline Profiles, ART giải thích mã DEX hoặc biên dịch nó qua JIT, mất thời gian. Với hồ sơ, ART biên dịch các phương thức được chỉ định thành mã gốc (AOT) trong khi cài đặt ứng dụng. Google tuyên bố rằng Baseline Profiles tăng tốc Cold Start 15–40% trên Android 9+ và lên đến 60% với các tối ưu ART của Android 12+. Để tạo hồ sơ, hãy sử dụng plugin androidx.benchmark:benchmark-baseline-profile-gradle-plugin.

App Startup Library

Thư viện androidx.startup cho phép sắp xếp thứ tự khởi tạo thành phần và thực thi nó trong một ContentProvider duy nhất. Thay vì nhiều ContentProviders từ các thư viện khác nhau (mỗi cái thêm 1–2 ms vào khởi động nguội), App Startup hợp nhất chúng thành một đồ thị phụ thuộc và khởi tạo theo đúng nhu cầu. Khi khởi động, chỉ các thành phần được đánh dấu bằng @Initializer cần thiết cho màn hình đầu tiên mới được thực thi. Đối với các thành phần còn lại, cờ needEarlyInit = false được đặt — chúng khởi động sau lần kết xuất đầu tiên.

kotlin
// App Startup Initializer — khởi tạo sau khi khởi động
class AnalyticsInitializer : Initializer<Unit> {
    override fun create(context: Context) {
        Analytics.init(context)
    }
    override fun dependencies() = listOf<Class<out Initializer<*>>>()
}

// Trong AndroidManifest.xml đánh dấu là tùy chọn
// <meta-data android:name="AnalyticsInitializer"
//     android:value="false" />

Giảm kích thước DEX

Kích thước tệp DEX ảnh hưởng trực tiếp đến thời gian tải ART. Sử dụng R8/ProGuard để làm rối và xóa mã chết (MinifyEnabled = true). Bật android:extractNativeLibs="false" trong tệp kê khai để APK không giải nén các tệp .so khi cài đặt. Đối với các dự án có hơn 10 theo dõi tham chiếu, chỉ thêm startup-priority cho màn hình đầu tiên. Mỗi phương thức thừa trong DEX thêm 0,5–2 ms vào thời gian tải và đối với ứng dụng có hơn 50k phương thức (multidex với primary dex) — lên đến 300 ms.

Cold Start trong Android Vitals

Android Vitals trong Google Play Console (phần Launch time) thu thập dữ liệu từ tất cả các thiết bị đã cài đặt ứng dụng, với điều kiện người dùng đã đồng ý chẩn đoán ẩn danh. Các chỉ số được chia thành ba loại: “tốt”, “trung bình”, “xấu”, tùy theo thời gian Cold Start.

Ngưỡng của Google

Google định nghĩa Cold Start “xấu” là thời gian vượt quá 5 giây trên bất kỳ thiết bị nào. Tuy nhiên, trên thực tế, đối với thiết bị cao cấp (Snapdragon 8 Gen), thời gian tốt là dưới 1,5 giây, đối với tầm trung — dưới 2,5 giây, đối với bình dân — dưới 4 giây. Android Vitals hiển thị trung vị cho mỗi mẫu thiết bị, cho phép hiểu thiết bị nào ứng dụng khởi động chậm. Nếu Cold Start xấu trên các thiết bị Samsung A-series hoặc Xiaomi Redmi, nguyên nhân thường là bộ nhớ flash chậm và RAM thấp (tăng tốc qua Baseline Profiles mang lại hiệu quả lớn nhất trên các thiết bị như vậy).

Google Play sử dụng chỉ số như thế nào

Ngoài việc hiển thị trong bảng điều khiển, chỉ số Cold Start ảnh hưởng đến đánh giá chất lượng ứng dụng trong Google Play Search. Các ứng dụng có tỷ lệ khởi động “xấu” cao sẽ nhận được nhãn “Cảnh báo hiệu suất” trên trang cài đặt, làm giảm tỷ lệ chuyển đổi. Theo Google (Android Performance Playbook, 2024), các ứng dụng đã giải quyết vấn đề Cold Start đã tăng tỷ lệ chuyển đổi cài đặt trung bình 5% và cải thiện khả năng giữ chân (D1) từ 3–7%.

Tích hợp với Firebase Performance

Để giám sát chi tiết hơn, hãy sử dụng Firebase Performance Monitoring. Nó theo dõi Cold Start ở cấp độ phiên, phân chia theo phiên bản ứng dụng và phiên bản Android. Không giống như Android Vitals, Firebase hiển thị sơ đồ dấu vết thời gian đã dành theo giai đoạn. Ví dụ: bạn có thể thấy rằng trong phiên bản 3.2.0, Application.onCreate mất 800 ms (do thư viện thông báo đẩy mới), trong khi ở phiên bản 3.2.1 — 200 ms (sau khi sửa lỗi).

Ví dụ mã để tối ưu

Dưới đây là hai ví dụ thực tế giúp tăng tốc Cold Start trực tiếp: di chuyển khởi tạo SDK sau khi khởi động và sử dụng SplashScreen API.

Di chuyển khởi tạo khỏi Application.onCreate

Một lỗi điển hình là khởi tạo tất cả SDK trong Application.onCreate. Dưới đây cho thấy cách di chuyển khởi tạo không quan trọng sang một coroutine được khởi chạy sau khi vẽ khung hình đầu tiên. Quan trọng: Firebase, Crashlytics và SDK báo cáo sự cố phải được khởi tạo khi khởi động — không thể trì hoãn vì chúng bắt lỗi trong khi khởi tạo các thành phần khác. Phần còn lại, hãy sử dụng lifecycleScope trong Activity đầu tiên.

kotlin
// ❌ Xấu — tất cả khởi tạo trong Application.onCreate
class App : Application() {
    override fun onCreate() {
        super.onCreate()
        Firebase.init(this) // quan trọng
        Analytics.init(this) // có thể sau
        Database.init(this) // có thể sau
        ImageLoader.init(this) // có thể sau
    }
}

// ✅ Tốt — Firebase khi khởi động, còn lại after inflate
class App : Application() {
    override fun onCreate() {
        super.onCreate()
        Firebase.init(this)
    }
}

// Trong MainActivity sau khung hình đầu tiên:
lifecycleScope.launchWhenResumed {
    initializeNonCriticalSdks()
}

SplashScreen API

Trên Android 12+, hãy sử dụng SplashScreen API chính thức hiển thị splash hệ thống (biểu tượng ứng dụng trên nền tối/sáng) ngay khi tiến trình khởi động. Điều này che giấu thời gian khởi tạo khỏi người dùng — họ thấy splash thay vì màn hình trắng. Đối với thiết bị cũ, hãy sử dụng theme-based splash (Theme.SplashScreen trong kiểu). Quan trọng: splash không nên kéo dài quá 300 ms — nếu ứng dụng chưa sẵn sàng vào lúc đó, hãy vẽ một bộ xương “cố định” (shimmer) và hiển thị tiến trình tải.

kotlin
// SplashScreen API — Android 12+
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        val splashScreen = installSplashScreen()
        splashScreen.setKeepOnScreenCondition {
            isReady.value == false
        }
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }
}

// Splash dựa trên chủ đề (Android 5-11)
// Trong themes.xml:
// <style name="Theme.App.Starting" parent="Theme.SplashScreen">
//   <item name="windowSplashScreenBackground">@color/white</item>
//   <item name="windowSplashScreenAnimatedIcon">@mipmap/ic_launcher</item>
// </style>

Câu hỏi thường gặp

Tại sao Cold Start trên giả lập nhanh hơn trên thiết bị thật?

Giả lập sử dụng máy tính chủ mạnh mẽ và mô phỏng bộ xử lý với tăng tốc phần cứng (HAXM / WHPX). Thiết bị thật, đặc biệt là thiết bị bình dân (bộ nhớ eMMC thay vì UFS), có I/O chậm hơn nhiều. Nên đo Cold Start trên thiết bị thật tầm trung để có dữ liệu thực tế.

Cold Start nào được coi là chấp nhận được?

Theo khuyến nghị của Google, Cold Start trung vị phải dưới 2 giây trên thiết bị tầm trung. Đối với thiết bị cao cấp — dưới 1,5 giây. Đối với thiết bị bình dân (2 GB RAM) có thể chấp nhận tối đa 4 giây, nhưng khuyến nghị tối ưu xuống 3 giây. Giá trị trên 5 giây được coi là nghiêm trọng.

Kích thước biểu tượng có ảnh hưởng đến tốc độ Cold Start không?

Gián tiếp — có. Nếu tệp kê khai chứa biểu tượng vector (AdaptiveIcon), nó phải được biên dịch thành drawable khi khởi động. Nếu biểu tượng chứa các đường dẫn phức tạp (pathData với hàng chục đường cong), quá trình biên dịch mất 10–30 ms. Sử dụng VectorDrawable với pathData đã tối ưu (qua SVGOMG hoặc Android Studio Vector Asset).

Có cần tối ưu Cold Start trong Feature Module không?

Có, nếu Feature Module (Android App Bundle) được tải theo yêu cầu, Cold Start của nó được đo từ thời điểm nhấn vào tính năng cho đến khung hình đầu tiên. Các mô-đun theo yêu cầu được tải qua Play Core Library và quá trình cài đặt chúng thêm 500–3000 ms vào thời gian khởi động. Tối ưu mã tính năng giống như mô-đun chính.

Multidex ảnh hưởng đến Cold Start như thế nào?

Các ứng dụng có hơn 64k phương thức yêu cầu Multidex. Điều này có nghĩa là ART phải tải nhiều tệp DEX, làm tăng thời gian Cold Start thêm 200–800 ms tùy thuộc vào số lượng tệp classes.dex. Sử dụng minSdk 21+ (ART hỗ trợ multidex gốc) và cấu hình primary dex qua --main-dex-list để giữ các lớp quan trọng trong tệp DEX đầu tiên.

Tổng kết

  • Cold Start — khởi động ứng dụng đầy đủ với tạo tiến trình mới, thời gian 1–5 giây
  • Đo qua ADB shell am start -S -W hoặc Macrobenchmark trong CI/CD
  • Bốn giai đoạn: fork → Application.onCreate → Activity.onCreate → khung hình đầu tiên
  • Tối ưu: khởi tạo trễ, Baseline Profiles, App Startup Library, nén R8
  • Google Play đánh giá Cold Start là “xấu” khi thời gian vượt quá 5 giây trên bất kỳ thiết bị nào
  • SplashScreen API trên Android 12+ che giấu thời gian khởi tạo sau splash hệ thống
  • Cứ 100 ms trì hoãn làm giảm 3% khả năng giữ chân người dùng

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.

Thảo luận dự án

Đọc thêm