Topik ini membantu Anda mengidentifikasi dan mengatasi masalah performa utama di aplikasi Anda.
Masalah performa utama
Ada banyak masalah yang dapat menyebabkan performa yang buruk dalam aplikasi, tetapi berikut adalah beberapa situasi umum yang harus diperhatikan di aplikasi Anda:
- Jank Scroll
- "Jank" adalah istilah yang digunakan untuk menggambarkan gangguan visual yang terjadi saat sistem tidak dapat membuat dan menyediakan frame pada waktunya untuk ditarik ke layar pada ritme yang diminta (60 hz, atau lebih tinggi). Jank paling terlihat saat aktivitas men-scroll, saat alur animasi yang seharusnya lancar mengalami gangguan. Gerakannya juga terjeda untuk satu atau beberapa frame karena aplikasi memerlukan waktu yang lebih lama untuk merender konten daripada durasi frame pada sistem.
- Aplikasi harus menargetkan rasio pembaruan 90 Hz. Kecepatan rendering tradisional telah
mencapai 60 Hz, tetapi banyak perangkat baru yang beroperasi dalam mode 90 Hz selama interaksi
pengguna seperti men-scroll, dan perangkat tertentu mendukung kecepatan yang lebih tinggi,
hingga 120 Hz.
- Untuk melihat kecepatan refresh yang digunakan perangkat pada waktu tertentu, aktifkan overlay menggunakan Developer Options > Show refresh rate di bagian Debugging.
-
- Latensi pengaktifan adalah jumlah waktu yang dibutuhkan antara mengetuk ikon aplikasi, notifikasi, atau titik entri lainnya dan data pengguna yang ditampilkan di layar.
Anda harus menargetkan dua sasaran pengaktifan ini di aplikasi Anda:
Start cold < 500 md: "Start cold" terjadi saat aplikasi yang diluncurkan tidak ada dalam memori sistem. Hal ini terjadi saat aplikasi diluncurkan pertama kali sejak dimulai ulang atau sejak proses aplikasi dihentikan oleh pengguna atau sistem.
Sebaliknya, "start warm" terjadi saat aplikasi sudah berjalan di latar belakang. Start cold memerlukan paling banyak upaya dari sistem karena harus memuat semuanya dari penyimpanan dan menginisialisasi aplikasi. Usahakan untuk mencapai sasaran start cold dengan waktu 500 md atau kurang.
Latensi P95/P99 sangat dekat dengan latensi median. Jika aplikasi terkadang membutuhkan waktu yang sangat lama untuk memulai, kepercayaan pengguna akan terkikis. IPC dan I/O yang tidak perlu selama jalur penting pengaktifan aplikasi dapat mengalami pertentangan kunci dan menimbulkan inkonsistensi ini.
Transisi yang tidak lancar
- Masalah ini timbul selama interaksi seperti beralih antar-tab atau memuat aktivitas baru. Jenis transisi ini harus memiliki animasi yang lancar dan tidak mencakup keterlambatan atau kedipan visual.
Ketidakefisienan daya
- Melakukan tugas akan menghabiskan baterai, dan melakukan tugas yang tidak perlu akan mengurangi masa pakai baterai.
Alokasi memori, yang berasal dari pembuatan objek baru dalam kode, dapat menjadi penyebab tugas yang signifikan dalam sistem. Ini karena tidak hanya alokasi tersebut memerlukan upaya dari Android Runtime, tetapi membebaskan objek tersebut nanti ("pembersihan sampah memori") juga memerlukan waktu dan upaya. Alokasi dan pengumpulan jauh lebih cepat dan efisien daripada sebelumnya, terutama untuk objek sementara. Jadi, jika panduan sebelumnya adalah untuk menghindari pengalokasian objek kapan pun memungkinkan, rekomendasinya sekarang adalah melakukan hal yang paling masuk akal bagi aplikasi dan arsitektur Anda; menghemat alokasi dengan risiko kode tidak dapat dipertahankan bukanlah pilihan yang tepat mengingat hal yang mampu dilakukan oleh ART.
Namun, masih ada upaya yang perlu dilakukan, sehingga perlu diingat apakah Anda mengalokasikan banyak objek di loop dalam, yang dapat menyebabkan masalah performa.
Mengidentifikasi masalah
Alur kerja yang direkomendasikan untuk mengidentifikasi dan memperbaiki masalah performa adalah sebagai berikut:
- Identifikasi perjalanan penting pengguna untuk diperiksa. Hal ini dapat mencakup:
- Alur pengaktifan umum, termasuk dari peluncur dan notifikasi.
- Layar apa pun tempat pengguna men-scroll data.
- Transisi antar-layar.
- Alur yang berjalan lama, seperti navigasi atau pemutaran musik.
- Periksa peristiwa yang terjadi selama alur tersebut menggunakan alat proses debug:
- Systrace atau Perfetto: Memungkinkan Anda melihat peristiwa yang sebenarnya terjadi di seluruh perangkat dengan data waktu yang tepat.
- Memory profiler: Memungkinkan Anda melihat alokasi memori yang terjadi pada heap.
- Simpleperf: Melihat flamegraph panggilan fungsi yang paling banyak menggunakan CPU selama periode tertentu. Saat Anda mengidentifikasi sesuatu yang memerlukan waktu lama di systrace, tetapi Anda tidak tahu alasannya, simpleperf dapat memberikan informasi tambahan.
Proses debug manual pada setiap pengujian yang dijalankan sangat penting untuk memahami dan mendebug masalah performa ini. Langkah-langkah di atas tidak dapat diganti dengan menganalisis data gabungan. Namun, menyiapkan pengumpulan metrik dalam pengujian otomatis serta di lapangan juga penting untuk memahami apa yang sebenarnya dilihat dan diidentifikasi pengguna saat terjadi regresi:
- Alur pengaktifan
- Metrik kolom: Waktu pengaktifan Konsol Play
- Pengujian Lab Jetpack Macrobenchmark: Pengaktifan
- Jank
- Metrik kolom
- Konsol Play frame vitals: Perlu diketahui bahwa dalam Konsol Play, Anda tidak dapat mempersempit metrik ke perjalanan pengguna tertentu, karena semua yang dilaporkan adalah keseluruhan jank di seluruh aplikasi.
- Pengukuran kustom dengan
FrameMetricsAggregator
: Anda dapat menggunakanFrameMetricsAggregator
untuk merekam metrik jank selama alur kerja tertentu.
- Pengujian lab
- Jetpack Macrobenchmark: Men-scroll
- Macrobenchmark mengumpulkan waktu render frame menggunakan perintah
dumpsys gfxinfo
yang mengelompokkan perjalanan pengguna. Ini adalah cara yang wajar untuk memahami variasi dalam jank selama perjalanan pengguna tertentu. MetrikRenderTime
, yang menyoroti lamanya waktu yang diperlukan untuk menggambar frame, lebih penting daripada jumlah frame yang mengalami jank untuk mengidentifikasi regresi atau peningkatan.
- Metrik kolom
Menyiapkan aplikasi untuk analisis performa
Penyiapan yang benar sangat penting untuk mendapatkan tolok ukur yang akurat, dapat diulang, dan dapat ditindaklanjuti dari aplikasi. Uji pada sistem yang semirip mungkin dengan produksinya, sambil menyembunyikan sumber derau. Di bagian berikut, terdapat langkah-langkah khusus APK dan khusus sistem yang dapat Anda ambil untuk mempersiapkan penyiapan pengujian, yang beberapa di antaranya adalah khusus kasus penggunaan.
Tracepoint
Aplikasi dapat menggunakan kodenya dengan peristiwa perekaman aktivitas khusus.
Saat aktivitas direkam, perekaman aktivitas menimbulkan overhead kecil (sekitar 5 μs) per bagian, jadi jangan letakkan di setiap metode. Hanya dengan merekam aktivitas bagian tugas yang lebih besar (>0,1 md) dapat memberikan insight yang signifikan tentang bottleneck.
Pertimbangan APK
Perhatian: Jangan ukur performa pada build debug.
Varian debug dapat berguna untuk pemecahan masalah dan melambangkan contoh stack,
tetapi variasi tersebut memiliki dampak non-linear yang parah terhadap performa. Perangkat yang menjalankan
Android 10 (API Level 29) dan yang lebih tinggi dapat menggunakan
profileable android:shell="true"
dalam manifesnya untuk mengaktifkan pembuatan profil dalam build rilis.
Gunakan konfigurasi penyingkatan kode berkelas produksi. Bergantung pada resource yang digunakan aplikasi Anda, hal ini dapat berdampak besar terhadap performa. Perlu diketahui bahwa konfigurasi ProGuard tertentu menghapus tracepoint, jadi pertimbangkan untuk menghapus aturan tersebut untuk konfigurasi yang Anda gunakan saat menjalankan pengujian.
Kompilasi
Kompilasikan aplikasi Anda di perangkat ke status yang diketahui (umumnya kecepatan atau profil kecepatan). Aktivitas JIT latar belakang dapat memiliki overhead performa yang signifikan, dan Anda akan sering menemukannya jika menginstal ulang APK di antara pengujian. Perintah yang harus dilakukan adalah:
adb shell cmd package compile -m speed -f com.google.packagename
Mode kompilasi 'kecepatan' akan mengompilasi aplikasi sepenuhnya; mode 'profil kecepatan' akan mengompilasi aplikasi berdasarkan profil jalur kode yang digunakan dan dikumpulkan selama penggunaan aplikasi. Terkadang sulit untuk mengumpulkan profil secara konsisten dan benar, jadi jika Anda memutuskan untuk menggunakannya, pastikan profil tersebut mengumpulkan apa yang Anda harapkan. Profil berada di sini:
/data/misc/profiles/ref/[package-name]/primary.prof
Perlu diketahui bahwa Macrobenchmark memungkinkan Anda langsung menentukan mode kompilasi.
Pertimbangan sistem
Untuk pengukuran level rendah dan fidelitas tinggi, kalibrasikan perangkat Anda. Jalankan perbandingan A/B di perangkat dan versi OS yang sama. Mungkin ada perbedaan yang signifikan dalam performa, bahkan pada jenis perangkat yang sama.
Di perangkat yang telah di-root, pertimbangkan untuk menggunakan
skrip lockClocks
untuk tolok ukur mikro. Di antara hal lain, skrip ini melakukan hal berikut:
- Menempatkan CPU pada frekuensi tetap.
- Menonaktifkan core kecil yang mengonfigurasi GPU.
- Menonaktifkan throttling termal.
Ini tidak direkomendasikan untuk pengujian yang berfokus pada pengalaman pengguna (seperti peluncuran aplikasi, pengujian DoU, dan pengujian jank), tetapi dapat menjadi penting untuk mengurangi derau dalam pengujian tolok ukur mikro.
Jika memungkinkan, pertimbangkan untuk menggunakan framework pengujian seperti Macrobenchmark, yang dapat mengurangi derau dalam pengukuran dan mencegah ketidakakuratan pengukuran.
Waktu pengaktifan aplikasi lambat: aktivitas trampolin yang tidak perlu
Aktivitas trampolin dapat memperpanjang waktu pengaktifan aplikasi yang tidak perlu, dan
penting untuk diketahui jika aplikasi melakukannya. Seperti yang dapat Anda lihat dalam contoh
rekaman aktivitas berikut, satu activityStart
langsung diikuti oleh
activityStart
lain tanpa frame yang digambar oleh aktivitas pertama.
Hal ini dapat terjadi pada titik entri notifikasi dan titik entri pengaktifan aplikasi biasa, dan sering kali dapat diatasi dengan pemfaktoran ulang. Misalnya, jika Anda menggunakan aktivitas tersebut untuk melakukan penyiapan sebelum aktivitas lain berjalan, faktorkan kode tersebut ke dalam komponen atau library yang dapat digunakan kembali.
Alokasi yang tidak diperlukan memicu seringnya GC
Anda dapat mengetahui bahwa Pembersihan Sampah Memori (GC) lebih sering daripada yang diharapkan dalam systrace.
Dalam hal ini, setiap 10 detik selama operasi yang berjalan lama adalah indikator bahwa aplikasi Anda mungkin melakukan alokasi secara tidak perlu tetapi konsisten dari waktu ke waktu:
Atau, Anda mungkin mengetahui bahwa callstack tertentu melakukan sebagian besar alokasi saat menggunakan Memory Profiler. Anda tidak perlu menghilangkan semua alokasi secara agresif, karena hal ini dapat membuat kode lebih sulit dipertahankan. Mulai dengan mengerjakan hotspot alokasi.
Frame yang mengalami jank
Pipeline grafis relatif rumit, dan mungkin ada perbedaan kecil yang terlibat dalam menentukan apakah pengguna pada akhirnya mungkin melihat penurunan frame; dalam kasus tertentu, platform dapat "menyelamatkan" frame menggunakan buffering. Namun, Anda dapat mengabaikan sebagian besar perbedaan kecil tersebut untuk mengidentifikasi frame yang bermasalah dengan mudah dari perspektif aplikasi Anda.
Jika frame digambar dengan sedikit tugas yang diperlukan dari aplikasi,
tracepoint Choreographer.doFrame()
terjadi pada ritme 16,7 md (dengan asumsi perangkat
60 FPS):
Jika memperkecil dan menavigasi rekaman aktivitas, terkadang Anda akan melihat frame memerlukan waktu sedikit lebih lama untuk diselesaikan, tetapi itu tidak masalah karena frame tersebut tidak memerlukan waktu lebih dari 16,7 md:
Jika Anda benar-benar melihat gangguan pada ritme teratur tersebut, itulah frame yang mengalami jank:
Dengan sedikit latihan, Anda akan dapat melihatnya dengan mudah.
Dalam kasus tertentu, Anda harus memperbesar tracepoint tersebut untuk mendapatkan informasi selengkapnya tentang tampilan yang sedang di-inflate atau hal yang dilakukan RecyclerView. Dalam kasus lain, Anda mungkin harus memeriksa lebih lanjut.
Untuk informasi selengkapnya tentang cara mengidentifikasi frame yang mengalami jank dan mendebug penyebabnya, lihat Rendering lambat.
Kesalahan umum RecyclerView
- Pembatalan validasi seluruh data cadangan
RecyclerView
yang tidak perlu. Hal ini dapat menyebabkan waktu rendering frame yang lama sehingga terjadi jank. Sebagai gantinya, batalkan validasi hanya data yang telah berubah untuk meminimalkan jumlah tampilan yang perlu diperbarui.- Lihat Mempresentasikan data
dinamis
untuk mengetahui cara menghindari panggilan
notifyDatasetChanged()
yang mahal, yang menyebabkan konten diperbarui, bukan diganti sepenuhnya.
- Lihat Mempresentasikan data
dinamis
untuk mengetahui cara menghindari panggilan
- Gagal mendukung
RecyclerView
bertingkat dengan benar, sehingga menyebabkanRecyclerView
internal dibuat ulang sepenuhnya setiap saat.- Setiap bagian dalam
RecyclerView
bertingkat harus memiliki kumpulanRecycledViewPool
untuk memastikan tampilan dapat didaur ulang di antara bagian dalamRecyclerView
.
- Setiap bagian dalam
- Tidak mengambil data yang memadai, atau tidak mengambil data secara tepat waktu. Mencapai bagian bawah daftar scroll dengan cepat dan perlu menunggu lebih banyak data dari server mungkin menyebalkan. Meskipun secara teknis ini bukan "jank", karena tidak ada tenggat frame yang terlewat, mengubah waktu dan kuantitas pengambilan data agar pengguna tidak perlu menunggu data dapat menjadi peningkatan UX yang signifikan.
Direkomendasikan untuk Anda
- Catatan: teks link ditampilkan saat JavaScript nonaktif
- Analisis dan pengoptimalan startup aplikasi {:#app-startup-analysis-optimization}
- Periode frozen
- Menulis Macrobenchmark