Setelah Anda memahami pengelolaan memori Android dan menyiapkan alat untuk mengukur penggunaan memori game, langkah berikutnya adalah mengurangi dan mengoptimalkannya secara aktif. Tetap berada dalam batas ketat Android akan membantu mencegah sistem menutup game Anda, menghentikan waktu startup yang lama, dan memastikan game Anda berjalan dengan baik di semua perangkat.
Panduan ini memberikan teknik praktis untuk memangkas jejak memori game Anda, khususnya berfokus pada pengoptimalan tingkat aset, konfigurasi khusus mesin, dan praktik terbaik pengelolaan memori.
Mengurangi memori di Unity
Karena desain arsitektur Unity, setelah alokator blok native dan heap terkelola diperluas, mesin cenderung mempertahankan halaman memori tersebut untuk digunakan kembali, bukan segera mengembalikannya ke sistem operasi (OS), bahkan setelah aset dirilis. Secara khusus, ruang alamat virtual (memori yang dicadangkan) tetap dicadangkan selama masa aktif proses, dan memori fisik (RSS) tidak segera diklaim kembali hingga beberapa siklus pembersihan sampah memori (GC) dan pemangkasan terjadi. Akibatnya, puncak memori sementara dapat menyebabkan memori residen tetap meningkat dalam waktu lama meskipun penggunaan sebenarnya menurun. Perilaku ini meningkatkan risiko error kehabisan memori (OOM) pada perangkat kelas bawah dan menurunkan stabilitas runtime secara keseluruhan.
Oleh karena itu, pengoptimalan memori Unity harus didekati melalui tiga pilar inti yang disesuaikan dengan perilaku mesin ini:
- Mengontrol penggunaan memori aktif untuk mencegah lonjakan memori puncak sejak awal.
- Mengelola format tekstur dan varian shader untuk memastikan aset dan resource native yang tidak diperlukan tidak dibuat instance-nya.
- Memfaktorkan ulang struktur kode runtime untuk menghilangkan alokasi yang tidak diperlukan pada heap terkelola guna meminimalkan frekuensi GC dan perluasan heap.
Untuk mengetahui informasi selengkapnya, lihat Pengoptimalan memori Unity.
Mengurangi memori di Unreal Engine
Di Unreal Engine, pipeline rendering fidelitas tinggi dan grafik dependensi objek yang kompleks dapat secara signifikan meningkatkan tekanan memori RSS anonim dan yang didukung file. Secara khusus, mengandalkan referensi tetap dan hierarki inheritance Blueprint yang mendalam akan memaksa aset terhubung yang tidak digunakan untuk dimuat ke dalam memori. Selain itu, permutasi shader yang berlebihan, kumpulan streaming tekstur yang tidak dioptimalkan, dan tabel relokasi ELF yang tidak dikompresi berkontribusi pada jejak memori dasar yang tinggi, sehingga meningkatkan risiko penghentian low memory killer (LMK).
Oleh karena itu, pengoptimalan memori Unreal Engine harus didekati melalui tiga pilar inti yang disesuaikan dengan perilaku mesin ini:
- Memisahkan data dan logika, mengganti referensi tetap atau kuat dengan referensi lunak atau lemah.
- Menghapus fitur pencahayaan seluler dan opsi permutasi yang tidak digunakan untuk meminimalkan objek status pipeline (PSO) dan target render yang berlebihan, sekaligus menerapkan kompresi ASTC dan menyesuaikan kumpulan streaming tekstur dengan profil perangkat.
- Mengaktifkan Kompresi Tabel Relokasi RELR dan APS untuk mengecilkan ukuran biner ELF dan mengurangi jejak memori fisik runtime.
Untuk mengetahui informasi selengkapnya, lihat Pengoptimalan memori Unreal.
Pengoptimalan multi-proses
Penggunaan memori proses yang di-cache dikecualikan dari perhitungan batas memori karena tidak berdampak pada aplikasi aktif. Menjalankan layanan dalam proses terisolasi yang terpisah akan membantu proses utama bertransisi ke status yang di-cache secepat mungkin, sehingga meningkatkan performa game Anda.
Untuk mengetahui informasi selengkapnya, lihat Cara melacak status dan memori proses, Cara mengisolasi proses layanan dengan Unity, dan Cara mengisolasi proses layanan dengan Unreal.
Mengurangi penggunaan memori dalam layanan yang dirasakan pengguna
Game Anda mungkin perlu menjalankan logika dalam layanan yang dirasakan pengguna untuk kasus penggunaan seperti menyelesaikan download besar atau untuk sistem chat suara latar belakang. Strategi ini dapat membantu Anda mengelola dan mengurangi penggunaan memori selama skenario ini.
Strategi untuk download besar
Strategi ini mungkin berlaku untuk download besar yang ingin Anda lanjutkan meskipun pengguna telah meminimalkan game Anda.
1. Mengisolasi proses download
Apa: Pastikan OS dapat segera mengklaim kembali memori yang tidak digunakan aplikasi Anda dengan melakukan download dalam proses terpisah, karena kemungkinan alokator memori dapat menyimpan halaman kumpulan memori dan menjaga memori RSS Anonim tetap tinggi secara artifisial meskipun setelah array dibebaskan. Saat Anda menghentikan atau keluar dari layanan dan proses secara eksplisit, memori akan dikembalikan ke kumpulan OS dan proses utama Anda tidak akan terpengaruh.
Di Unity: Lepaskan download ke Android native
Serviceyang dideklarasikan dengan proses sepertiandroid:process=":downloader"dalam Manifes kustom dan panggil dengan JNIAndroidJavaClassUnity. Pastikan untuk menghentikan proses saat download selesai. Lihat Menjalankan layanan yang dapat dirasakan dalam proses terpisah dengan Unity untuk panduan yang lebih mendetail.Di Unreal: Deklarasikan Android kustom
Servicedengan proses sepertiandroid:process=":downloader"menggunakan Unreal Plugin Language, dan picu dengan C++ JNI. Pastikan untuk menghentikan proses saat download selesai. Lihat Menjalankan layanan yang dapat dirasakan dalam proses terpisah dengan Unreal untuk panduan yang lebih mendetail.Untuk Android Native: Deklarasikan
ServicediAndroidManifestdengan proses sepertiandroid:process=":downloader". Jalankan download dalam proses terisolasi ini, dan panggilProcess.killProcess(Process.myPid())saat download selesai.
Manfaat: Mengurangi durasi memori disimpan, dan memungkinkan download dilanjutkan sambil melepaskan memori yang digunakan oleh proses utama yang lebih besar.
2. Streaming download langsung ke disk
Apa: Streaming data langsung dari soket jaringan ke disk dengan menggunakan buffer yang dapat digunakan kembali berukuran kecil dan tetap, bukan mengakumulasikan respons jaringan ke dalam array besar sebelum menuliskannya.
Di Unity: Hindari penggunaan
DownloadHandlerBufferuntuk paket aset atau file besar, karena akan mengalokasikan buffer memori native yang setara dengan ukuran file (memori RSS Anonim). Sebagai gantinya, gunakanDownloadHandlerFileuntuk melakukan streaming byte secara native ke disk di thread latar belakang.Di Unreal: Salurkan potongan data yang masuk langsung ke
FArchive(arsip yang didukung file menggunakan File Manager Unreal) denganSetResponseBodyReceiveStream(), bukan menambahkan payload dariIHttpRequestkeTArray<uint8>.Untuk Android Native: Salurkan
InputStreamkeFileOutputStreammenggunakan buffer gabungan, bukan memanggil.readBytes()atau.string()pada respons HTTP.
Manfaat: Mengurangi penggunaan memori puncak
3. Streaming dekompresi file yang didownload
Apa: Jika download Anda dikompresi, gabungkan aliran input jaringan Anda dalam dekompresor streaming seperti ZipInputStream, bukan mendownload file, memuatnya ke RAM, lalu mengekstraknya.
Manfaat: Mengurangi penggunaan memori puncak
4. Mendelegasikan ke OS
Apa: Untuk menghindari pengelolaan memori latar belakang sepenuhnya, delegasikan pekerjaan ke API native Android.
WorkManageradalah wrapper modern yang direkomendasikan di sekitarJobSchedulertingkat OS. Untuk Android 14+,WorkManagersecara otomatis menangani download yang dipicu pengguna sebagai tugas Transfer Data yang Dimulai Pengguna (UIDT). Tindakan ini berjalan di dalam proses aplikasi Anda, jadi Anda tetap harus melakukan streaming langsung ke disk untuk meminimalkan penggunaan memori. UIDT melindungi aplikasi Anda dari error Memori Rendah dengan memungkinkan OS menjeda dan melanjutkan download Anda dengan lancar jika resource sistem menjadi terbatas.DownloadManagerberjalan dalam proses sistem terpisah dan tidak mengaitkan penggunaan memori untuk download ke aplikasi Anda. Aplikasi Anda akan menerima notifikasi siaran saat file didownload dan siap.
Manfaat: WorkManager membantu menangani skenario memori rendah, dan DownloadManager mengurangi penggunaan memori aplikasi Anda.
Strategi untuk layanan tambahan
Strategi ini mungkin berlaku untuk layanan tambahan yang dijalankan game secara paralel dengan proses game utama, seperti chat suara latar belakang.
1. Mengisolasi proses
Apa: Pisahkan fitur, misalnya solusi chat suara Anda, dari game engine utama. Misalnya, Anda dapat menjalankan pengambilan mikrofon dan
streaming jaringan di dalam layanan latar depan Android yang ditetapkan ke proses terpisah (dideklarasikan dalam Manifes, seperti dengan android:process=":voice").
Manfaat: Saat aplikasi diminimalkan, proses game utama yang berat dapat turun ke status yang di-cache dengan prioritas lebih rendah, sementara layanan tambahan yang lebih ringan akan terus berada dalam status layanan yang dirasakan pengguna.
2. Memangkas memori dalam proses yang tidak digunakan
Apa: Jika layanan tambahan terlalu terintegrasi ke dalam mesin game untuk dipisahkan, coba kurangi beban sebanyak mungkin dari proses segera setelah game berada di latar belakang/diminimalkan. Pertimbangkan untuk menghapus cache tekstur, membongkar scene yang tidak penting, menurunkan kecepatan render dan tick mesin ke 0, dan memanggil pengumpulan sampah secara eksplisit.
Di Unity: Lakukan pemangkasan ini saat
OnApplicationPause()diaktifkan.Resources.UnloadUnusedAssets()mungkin berguna.Di Unreal: Ikat logika pemangkasan ke delegasi
ApplicationWillEnterBackgroundDelegate.Untuk Android Native: Lakukan pemangkasan di
onPause()atauonStop()sebagaimana mestinya. OS dapat mencoba memanggil implementasi Anda darionTrimMemory()sebelum menghentikan proses menggunakan memori tinggi.
Manfaat: Mengurangi penggunaan memori yang tidak diperlukan saat game tidak berada di latar depan.