Berapa jumlah maksimum RAM yang bisa digunakan aplikasi?

145

Saya cukup ingin tahu tentang pertanyaan ini mengenai manajemen memori sistem operasi Android, jadi saya berharap jawaban yang cukup terperinci tentang topik itu.

Apa yang ingin saya ketahui:

  • Berapa jumlah maksimum memori (dalam megabita / sebagai persentase dari total RAM) yang dapat digunakan oleh aplikasi Android (yang bukan aplikasi sistem)?
  • Apakah ada perbedaan antara versi Android ?
  • Apakah ada perbedaan mengenai produsen perangkat?

Dan yang paling penting:

  • Apa yang dianggap / apa itu tergantung pada ketika datang ke sistem menentukan berapa banyak RAM aplikasi dapat digunakan saat runtime (dengan asumsi bahwa maksimum memori per aplikasi bukan angka statis)?

Apa yang saya dengar sejauh ini (hingga 2013):

  • Perangkat Android awal memiliki batas per aplikasi 16MB
  • Nanti tutup ini meningkat menjadi 24MB atau 32MB

Apa yang membuat saya sangat penasaran:

Kedua batas ini sangat rendah.

Saya baru saja mengunduh Android Task Manager untuk memeriksa RAM perangkat saya. Apa yang saya perhatikan adalah bahwa ada aplikasi yang menggunakan sekitar 40-50 megabyte RAM, yang jelas lebih dari penggunaan RAM maksimum yang disebutkan katakanlah 32 MB. Jadi, bagaimana Android menentukan berapa banyak RAM yang bisa digunakan aplikasi? Bagaimana mungkin aplikasi melebihi batas itu?

Selain itu, saya perhatikan bahwa beberapa aplikasi tambang saya mogok (terbunuh oleh sistem?) Dengan OutOfMemoryException saat menggunakan sekitar 30-40 Megabita. Di sisi lain, saya memiliki aplikasi yang berjalan di ponsel saya menggunakan 100 MB dan lebih banyak setelah beberapa waktu (mungkin karena kebocoran memori) yang tidak crash atau terbunuh. Jadi itu jelas juga tergantung pada aplikasi itu sendiri ketika datang untuk menentukan berapa banyak RAM yang dapat dihemat. Bagaimana ini mungkin? (Saya melakukan tes dengan HTC One S dengan 768 MB RAM)

Penafian: Saya TIDAK berafiliasi dengan aplikasi Android Task Manager.

Philipp Jahoda
sumber

Jawaban:

119

Berapa jumlah maksimum memori (dalam Megabytes / sebagai persentase dari total RAM) yang dapat digunakan oleh aplikasi Android (yang bukan aplikasi sistem)?

Itu bervariasi berdasarkan perangkat. getMemoryClass()padaActivityManager akan memberi Anda nilai untuk perangkat kode Anda berjalan.

Apakah ada perbedaan antara versi Android?

Ya, sejauh persyaratan OS telah meningkat selama bertahun-tahun, dan perangkat harus menyesuaikan agar sesuai.

Apakah ada perbedaan mengenai produsen perangkat?

Ya, sejauh pabrikan membuat perangkat, dan ukurannya bervariasi menurut perangkat.

"Faktor samping" manakah yang dipertimbangkan ketika menentukan berapa banyak RAM yang dapat digunakan suatu aplikasi?

Saya tidak tahu apa artinya "faktor samping".

Perangkat awal memiliki batas per aplikasi 16MB; Perangkat kemudian meningkat menjadi 24MB atau 32MB

Itu benar. Resolusi layar adalah penentu yang signifikan, karena resolusi yang lebih besar berarti bitmap yang lebih besar, sehingga tablet dan ponsel resolusi tinggi akan cenderung memiliki nilai yang lebih tinggi. Misalnya, Anda akan melihat perangkat dengan tumpukan 48MB, dan saya tidak akan terkejut jika ada nilai yang lebih tinggi dari itu.

Bagaimana mungkin aplikasi melebihi batas itu?

Anda menganggap bahwa pembuat aplikasi itu tahu apa yang dia lakukan. Menimbang bahwa penggunaan memori suatu aplikasi sulit untuk ditentukan oleh seorang insinyur inti Android , saya tidak akan berasumsi bahwa aplikasi tersebut perlu memberikan hasil yang sangat akurat.

Karena itu, kode asli (NDK) tidak tunduk pada batas tumpukan. Dan, sejak Android 3.0, aplikasi dapat meminta "tumpukan besar", biasanya dalam kisaran ratusan MB, tetapi itu dianggap bentuk yang buruk untuk sebagian besar aplikasi.

Selain itu, saya perhatikan bahwa beberapa aplikasi saya mengalami crash dengan OutOfMemoryException saat menggunakan sekitar 30-40 Megabita.

Ingatlah bahwa pengumpul sampah Android bukanlah pengumpul sampah pemadatan. Pengecualian memang seharusnya CouldNotFindSufficientlyLargeBlockOfMemoryException, tapi itu mungkin dianggap terlalu bertele-tele. OutOfMemoryExceptionberarti Anda tidak dapat mengalokasikan blok yang Anda minta , bukan berarti Anda telah kehabisan tumpukan Anda seluruhnya.

CommonsWare
sumber
Saya tidak mengerti tentang tabel, saya punya ponsel Xperia X yang memiliki resolusi sekitar 1080 x 1920 yang merupakan resolusi besar, dan perangkat lain Samsung Tab 4 yang resolusinya adalah 800 x 1280, jadi butuh pekerjaan ram yang sama, tolong bimbing saya karena ponsel dilengkapi dengan 3GB RAM dan tab hadir dengan 1.5GB RAM, jadi tablet menempati ram besar karena layar besar?
Rahul Mandaliya
@RahulMandaliya: Saya minta maaf, tapi saya tidak mengerti kekhawatiran Anda atau apa hubungannya dengan pertanyaan ini. Anda mungkin ingin membuka pertanyaan Stack Overflow terpisah di mana Anda menjelaskan secara terperinci apa yang menjadi perhatian Anda.
CommonsWare
15

Ini adalah akhir tahun 2018 sehingga banyak hal telah berubah.

Pertama-tama: jalankan aplikasi Anda dan buka tab Android Profiler di Android Studio. Anda akan melihat berapa banyak memori yang dikonsumsi, Anda akan terkejut tetapi dapat mengalokasikan banyak RAM.

Juga di sini adalah artikel yang bagus dalam dokumen resmi dengan instruksi terperinci tentang cara menggunakan Memory Profiler yang dapat memberi Anda pandangan mendalam tentang manajemen memori Anda.

Tetapi dalam sebagian besar kasus, Profiler Android reguler Anda sudah cukup untuk Anda.

masukkan deskripsi gambar di sini

Biasanya, aplikasi dimulai dengan alokasi RAM 50 MB tetapi langsung melonjak hingga 90 MB ketika Anda mulai memuat beberapa foto dalam memori. Saat Anda membuka Aktivitas dengan ViewPager dengan foto yang dimuat sebelumnya (masing-masing 3,5Mb), Anda bisa mendapatkan 190Mb dengan mudah dalam hitungan detik.

Tetapi ini tidak berarti Anda memiliki masalah dengan manajemen memori.

Saran terbaik yang bisa saya berikan adalah mengikuti pedoman dan praktik terbaik, gunakan perpustakaan teratas untuk memuat gambar (Glide, Picasso) dan Anda akan baik-baik saja.


Tetapi jika Anda perlu menyesuaikan sesuatu dan Anda benar-benar perlu tahu berapa banyak memori yang dapat Anda alokasikan secara manual, Anda bisa mendapatkan total memori bebas dan menghitung bagian yang telah ditentukan sebelumnya (dalam%) dari itu. Dalam kasus saya, saya perlu men-cache foto yang didekripsi dalam memori sehingga saya tidak perlu mendekripsi mereka setiap kali pengguna menelusuri daftar.

Untuk tujuan ini, Anda dapat menggunakan kelas LruCache siap pakai . Ini adalah kelas cache yang secara otomatis melacak berapa banyak memori yang dialokasikan objek Anda (atau jumlah instance) dan menghapus yang tertua untuk menjaga yang terbaru berdasarkan riwayat penggunaannya. Berikut adalah tutorial yang bagus tentang cara menggunakannya.

Dalam kasus saya, saya membuat 2 contoh cache: untuk jempol dan lampiran. Jadikan mereka statis dengan akses tunggal sehingga tersedia secara global di seluruh aplikasi.

kelas cache:

public class BitmapLruCache extends LruCache<Uri, byte[]> {

    private static final float CACHE_PART_FOR_THUMBS_PRC = 0.01f; // 1% (Nexus 5X - 5Mb)
    private static final float CACHE_PART_FOR_ATTACHMENTS_PRC = 0.03f;// 3% (Nexus 5X - 16Mb)
    private static BitmapLruCache thumbCacheInstance;
    private static BitmapLruCache attachmentCacheInstance;

public static synchronized BitmapLruCache getDecryptedThumbCacheInstance() {
    if (thumbCacheInstance == null) {

        int cacheSize = getCacheSize(CACHE_PART_FOR_THUMBS_PRC);
    //L.log("creating BitmapLruCache for Thumb with size: " + cacheSize + " bytes");
        thumbCacheInstance = new BitmapLruCache(cacheSize);
        return thumbCacheInstance;
    } else {
        return thumbCacheInstance;
    }
}

public static synchronized BitmapLruCache getDecryptedAttachmentCacheInstance() {
    if (attachmentCacheInstance == null) {

        int cacheSize = getCacheSize(CACHE_PART_FOR_ATTACHMENTS_PRC);
    //            L.log("creating BitmapLruCache for Attachment with size: " + cacheSize + " bytes");
        attachmentCacheInstance = new BitmapLruCache(cacheSize);
        return attachmentCacheInstance;
    } else {
        return attachmentCacheInstance;
    }
}

private BitmapLruCache(int maxSize) {
    super(maxSize);
}

public void addBitmap(Uri uri, byte[] bitmapBytes) {
    if (get(uri) == null && bitmapBytes != null)
        put(uri, bitmapBytes);
}

public byte[] getBitmap(Uri uri) {
    return get(uri);
}


@Override
protected int sizeOf(Uri uri, byte[] bitmapBytes) {
    // The cache size will be measured in bytes rather than number of items.
    return bitmapBytes.length;
}
}

Ini adalah bagaimana saya menghitung RAM gratis yang tersedia dan berapa banyak yang bisa saya gigit darinya:

private static int getCacheSize(float partOfTotalFreeMemoryToUseAsCache){
    final long maxMemory = Runtime.getRuntime().maxMemory();
    //Use ... of available memory for List Notes thumb cache
    return (int) (maxMemory * partOfTotalFreeMemoryToUseAsCache);
}

Dan ini adalah bagaimana saya menggunakannya dalam Adaptor untuk mendapatkan gambar dalam tembolok:

byte[] decryptedThumbnail = BitmapLruCache.getDecryptedThumbCacheInstance().getBitmap(thumbUri);

dan bagaimana saya mengaturnya ke dalam cache di latar belakang (AsyncTask biasa):

BitmapLruCache.getDecryptedThumbCacheInstance().addBitmap(thumbUri, thumbBytes); 

Aplikasi saya menargetkan API 19+ sehingga perangkat tidak lama dan bagian RAM yang tersedia ini cukup baik untuk cache dalam kasus saya (1% dan 3%).

Fakta menyenangkan: Android tidak memiliki API atau peretasan lain untuk mendapatkan jumlah memori yang dialokasikan untuk aplikasi Anda, itu dihitung dengan cepat berdasarkan berbagai faktor.


PS Saya menggunakan bidang kelas statis untuk menyimpan cache tetapi sesuai dengan pedoman Android terbaru direkomendasikan untuk menggunakan komponen arsitektur ViewModel untuk tujuan itu.

Kirill Karmazin
sumber