Bir uygulamanın kullanabileceği maksimum RAM miktarı nedir?


147

Android işletim sisteminin bellek yönetimi ile ilgili bu soruyu oldukça merak ediyorum, bu yüzden bu konuda oldukça ayrıntılı bir cevap bekliyorum.

Bilmek istediğim şey:

  • Bir Android uygulamasının (bu bir sistem uygulaması olmayan) kullanabileceği maksimum bellek miktarı ( megabayt cinsinden / toplam RAM'in yüzdesi olarak) nedir?
  • Android sürümleri arasında herhangi bir fark var mı?
  • Cihazın üreticisiyle ilgili herhangi bir farklılık var mı?

Ve en önemlisi:

  • Ne düşünülüyor / neye bağlı Bu, bir uygulama zamanında kullanabileceğiniz ne kadar RAM belirleyen sistemine gelince (uygulama başına bellek maksimum statik numarası olmadığını varsayarak)?

Şimdiye kadar duyduklarım (2013'e kadar):

  • İlk Android cihazların uygulama başına 16MB sınırı vardı
  • Daha sonra bu sınır 24MB veya 32MB'ye yükseltildi

Beni çok meraklandıran şey:

Bu sınırların her ikisi de çok düşük.

Yakın zamanda Android Görev Yöneticisini indirdimCihazımın RAM'ini kontrol etmek indirdim. Fark ettiğim şey, 40-50 megabayt RAM kullanan uygulamalar olduğu, bu da 32 MB diyelim belirtilen maksimum RAM kullanımından daha fazla abartılı olduğu. Peki Android bir uygulamanın ne kadar RAM kullanabileceğini nasıl belirler? Uygulamaların bu sınırı aşması nasıl mümkün olabilir?

Ayrıca, yaklaşık 30-40 Megabayt kullanırken bazı uygulamaların OutOfMemoryException ile çöktüğünü (sistem tarafından öldürüldü?) Fark ettim . Öte yandan, telefonumda bir süre sonra (muhtemelen bellek sızıntıları nedeniyle) 100 MB ve daha fazlasını kullanan , çökmeyen veya ölmeyen uygulamalarım var. Bu nedenle , RAM'in ne kadar korunabileceğini belirleme konusunda uygulamanın kendisine de bağlı olduğu açıktır . Bu nasıl mümkün olabilir? (Testlerimi 768 MB RAM'e sahip bir HTC One S ile gerçekleştirdim)

Feragatname: Android Görev Yöneticisi uygulamasına hiçbir şekilde bağlı DEĞİLİM.

Yanıtlar:


119

Bir Android uygulamasının (bu bir sistem uygulaması olmayan) kullanabileceği maksimum bellek miktarı (Megabayt cinsinden / toplam RAM'in yüzdesi olarak) nedir?

Bu, cihaza göre değişir. getMemoryClass()onActivityManager size kodunuzun üzerinde çalıştığı cihazın değerini verecektir.

Android sürümleri arasında herhangi bir fark var mı?

Evet, işletim sistemi gereksinimleri yıllar içinde arttığı ve cihazların buna uyacak şekilde ayarlanması gerektiği ölçüde.

Cihazın üreticisiyle ilgili farklılıklar var mı?

Evet, üreticilerin cihaz ürettiği ve boyutu cihaza göre değiştiği ölçüde.

Bir uygulamanın ne kadar RAM kullanabileceğini belirlerken hangi "yan faktörler" dikkate alınır?

"Yan faktörlerin" ne anlama geldiği hakkında hiçbir fikrim yok.

İlk cihazların uygulama başına 16MB sınırı vardı; Daha sonra cihazlar bunu 24MB veya 32MB'ye yükseltti

Bu doğru. Daha büyük çözünürlükler daha büyük bit eşlemler anlamına geldiğinden ekran çözünürlüğü önemli bir belirleyicidir ve bu nedenle tabletler ve yüksek çözünürlüklü telefonlar henüz daha yüksek değerlere sahip olma eğiliminde olacaktır. Örneğin, 48MB'lık yığınlara sahip cihazlar göreceksiniz ve bundan daha yüksek değerler olsa şaşırmam.

Uygulamaların bu sınırı aşması nasıl mümkün olabilir?

Bu uygulamanın yazarının ne yaptığını bildiğini varsayarsınız. Bir uygulamanın bellek kullanımını belirlemenin çekirdek bir Android mühendisi için zor olduğunu düşünürsek, söz konusu uygulamanın özellikle doğru sonuçlar vermesi gerekmediğini varsayıyorum.

Bununla birlikte, yerel kod (NDK) yığın sınırına tabi değildir. Ve Android 3.0'dan beri uygulamalar, genellikle yüzlerce MB aralığında "büyük bir yığın" isteyebilir, ancak bu çoğu uygulama için zayıf bir biçim olarak kabul edilir.

Ayrıca, bazı uygulamalarımın yaklaşık 30-40 Megabayt kullanırken bir OutOfMemoryException ile çöktüğünü fark ettim.

Android çöp toplayıcısının sıkıştıran bir çöp toplayıcı olmadığını unutmayın. Bunun istisnası gerçekten olmalı CouldNotFindSufficientlyLargeBlockOfMemoryException, ama bu muhtemelen çok uzun sürdü. yığınınızı tamamen tüketmediğinizden değil, talep ettiğiniz bloğu tahsis edemeyeceğinizOutOfMemoryException anlamına gelir .


Tabloyu anlayamıyorum, 1080 x 1920 çözünürlüğü olan Xperia X cep telefonum var ve çözünürlüğü 800 x 1280 olan başka bir cihaz Samsung Tab 4 var, bu yüzden aynı koç mesleğini al, lütfen bana rehberlik et çünkü cep telefonu ile birlikte geliyor 3GB RAM ve sekme 1.5GB RAM ile birlikte gelir, yani tablet büyük ekran nedeniyle büyük ram mı işgal ediyor?
Rahul Mandaliya

@RahulMandaliya: Üzgünüm ama endişenizi veya bu soruyla ne alakası olduğunu anlamıyorum. Endişenizin ne olduğunu ayrıntılı olarak açıkladığınız ayrı bir Stack Overflow sorusu açmak isteyebilirsiniz.
CommonsWare

15

2018'in sonu olduğundan işler değişti.

Her şeyden önce: uygulamanızı çalıştırın ve Android Studio'da Android Profiler sekmesini açın. Ne kadar hafıza tükettiğini göreceksiniz, şaşıracaksınız ama çok fazla RAM ayırabiliyor.

Ayrıca burada, bellek yönetiminize derinlemesine bir bakış sağlayabilecek, Bellek Profilcisi'nin nasıl kullanılacağına ilişkin ayrıntılı talimatlar içeren resmi belgelerde harika bir makale bulunmaktadır.

Ancak çoğu durumda, normal Android Profilerınız sizin için yeterli olacaktır.

görüntü açıklamasını buraya girin

Genellikle, bir uygulama 50Mb RAM tahsisi ile başlar, ancak hafızaya bazı fotoğrafları yüklemeye başladığınızda anında 90Mb'ye kadar atlar. Önceden yüklenmiş fotoğraflar (her biri 3,5Mb) içeren bir ViewPager ile Activity'i açtığınızda, 190Mb'yi saniyeler içinde kolayca alabilirsiniz.

Ancak bu, bellek yönetimi ile ilgili sorunlarınız olduğu anlamına gelmez.

Verebileceğim en iyi tavsiye, yönergeleri ve en iyi uygulamaları takip etmek, resim yüklemek için en iyi kitaplıkları kullanmak (Glide, Picasso) ve iyi olacaksın.


Ancak bir şeyi uyarlamanız gerekiyorsa ve manuel olarak ne kadar bellek ayırabileceğinizi gerçekten bilmeniz gerekiyorsa, toplam boş bellek elde edebilir ve bunun önceden belirlenmiş bir kısmını (% olarak) hesaplayabilirsiniz. Benim durumumda, şifresi çözülmüş fotoğrafları bellekte önbelleğe almam gerekiyordu, böylece kullanıcı listeyi her kaydırdığında bunların şifresini çözmeme gerek kalmadı.

Bu amaçla kullanıma hazır LruCache sınıfını kullanabilirsiniz . Nesnelerinizin ne kadar bellek ayırdığını (veya örnek sayısını) otomatik olarak izleyen ve kullanım geçmişlerine göre en eskiyi saklamak için en eskisini kaldıran bir önbellek sınıfıdır. İşte nasıl kullanılacağına dair harika bir öğretici.

Benim durumumda, 2 önbellek örneği oluşturdum: başparmaklar ve ekler için. Tekil erişimle onları statik hale getirdi, böylece uygulama genelinde küresel olarak kullanılabilirler.

önbellek sınıfı:

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;
}
}

Mevcut boş RAM'i şu şekilde hesaplıyorum ve bundan ne kadar ısırabilirim:

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);
}

Ve Adaptörler'de önbelleğe alınmış görüntüyü almak için bu şekilde kullanıyorum:

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

ve arka planda önbelleğe nasıl ayarladığımı (normal AsyncTask):

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

Uygulamam API 19 + 'yı hedeflediğinden cihazlar eski değil ve kullanılabilir RAM'in bu kısımları benim durumumda önbellek için yeterince iyi (% 1 ve% 3).

Eğlenceli gerçek: Android'in uygulamanıza ayrılan bellek miktarını almak için herhangi bir API'si veya başka hack'leri yoktur, çeşitli faktörlere göre anında hesaplanır.


Not: Bir önbelleği tutmak için statik bir sınıf alanı kullanıyorum, ancak en son Android yönergelerine göre, bu amaç için ViewModel mimari bileşeninin kullanılması önerilmektedir .


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.