Android'de uygulama yığını boyutunu algılama


Yanıtlar:


453

"Uygulama yığını boyutu kullanılabilir" ifadenizi düşünmenin iki yolu vardır:

  1. Zor bir hata tetiklenmeden önce uygulamam ne kadar yığın kullanabilir? Ve

  2. Ne kadar yığın gerektiğini benim app kullanımı kullanıcının cihazının Android işletim sistemi sürümü ve donanım kısıtlamaları verilen?

Yukarıdakilerin her birini belirlemek için farklı bir yöntem vardır.

Yukarıdaki madde 1 için: maxMemory()

aşağıdaki gibi çağrılabilir (örneğin, ana faaliyetinizin onCreate()yönteminde):

Runtime rt = Runtime.getRuntime();
long maxMemory = rt.maxMemory();
Log.v("onCreate", "maxMemory:" + Long.toString(maxMemory));

Bu yöntem, uygulamanızın toplam toplam bayt yığınını kullanmasına izin verildiğini gösterir.

Yukarıdaki 2. madde için: getMemoryClass()

aşağıdaki gibi çağrılabilir:

ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
int memoryClass = am.getMemoryClass();
Log.v("onCreate", "memoryClass:" + Integer.toString(memoryClass));

Bu yöntem , mevcut aygıtın sınırlarına ve kaba bir şekilde / döngüsüne tekrar tekrar zorlanmadan çalışacak diğer uygulamaların haklarına düzgün bir şekilde saygı duymak istiyorsa , uygulamanızın yaklaşık kaç megabayt yığın kullanması gerektiğini belirtir. Fil uygulamanız Android jakuzide banyo yaparken hafızanın dışına çıktı.onStop()onResume()

Bu ayrım, bildiğim kadarıyla açıkça belgelenmemiştir, ancak bu hipotezi beş farklı Android cihazda test ettim (aşağıya bakın) ve bunun doğru bir yorum olduğunu kendi memnuniyetimle doğruladım.

Android'in stok sürümü için, maxMemory()genellikle belirtildiği gibi yaklaşık aynı sayıda megabayt döndürür getMemoryClass()(yani, ikinci değerin yaklaşık bir milyon katı).

İki yöntemin birbirinden ayırabileceği tek durum, CyanogenMod gibi bir Android sürümü çalıştıran ve kullanıcının her bir uygulama için bir yığın boyutuna ne kadar izin verilmesi gerektiğini manuel olarak seçmesine izin veren köklü bir cihazda . Örneğin, CM'de bu seçenek "CyanogenMod ayarları" / "Performans" / "VM yığın boyutu" altında görünür.

NOT: Cihazınız için normalden daha küçük bir değer seçerseniz, BU DEĞERİ AYARLA SİSTEMİNİZİ EL İLE MESAJLAYABİLECEĞİNİZİ DİKKAT EDİN.

İşte döndürdüğü değerleri gösteren benim test sonuçları maxMemory()ve getMemoryClass()her biri için iki farklı (el-set) yığın değerleri kullanarak CyanogenMod çalışan dört farklı cihazlar için:

  • G1:
    • VM Yığın Boyutu 16 MB olarak ayarlandığında:
      • maxBellek: 16777216
      • getMemoryClass: 16
    • VM Yığın Boyutu 24 MB olarak ayarlandığında:
      • maxBellek: 25165824
      • getMemoryClass: 16
  • Moto Droid:
    • VM Yığın Boyutu 24 MB olarak ayarlandığında:
      • maxBellek: 25165824
      • getMemoryClass: 24
    • VM Yığın Boyutu 16 MB olarak ayarlandığında:
      • maxBellek: 16777216
      • getMemoryClass: 24
  • Nexus One:
    • VM Yığın boyutu 32 MB olarak ayarlandığında:
      • maxBellek: 33554432
      • getMemoryClass: 32
    • VM Yığın boyutu 24 MB olarak ayarlandığında:
      • maxBellek: 25165824
      • getMemoryClass: 32
  • Viewsonic GTab:
    • VM Yığın Boyutu 32 olarak ayarlandığında:
      • maxBellek: 33554432
      • getMemoryClass: 32
    • VM Yığın Boyutu 64 olarak ayarlandığında:
      • maxBellek: 67108864
      • getMemoryClass: 32

Yukarıdakilere ek olarak, Ice Cream Sandwich çalıştıran bir Novo7 Paladin tablet üzerinde de test yaptım. Bu, esasen ICS'nin stok versiyonuydu, ancak tableti tüm işletim sisteminin yerini almayan basit bir işlemle köklendirdim ve özellikle yığın boyutunun manuel olarak ayarlanmasına izin verecek bir arayüz sağlamaz.

Bu cihaz için sonuçlar şunlardır:

  • Novo7
    • maxBellek: 62914560
    • getMemoryClass: 60

Ayrıca (aşağıdaki bir yorumda Kishore başına):

  • HTC One X
    • maxBellek: 67108864
    • getMemoryClass: 64

Ve (akauppi'nin yorumu uyarınca):

  • Samsung Galaxy Core Plus
    • maxMemory: (Yorumda belirtilmemiş)
    • getMemoryClass: 48
    • largeMemoryClass: 128

Cmcromance'den bir yorum başına:

  • Galaxy S3 (Jelly Bean) büyük yığın
    • maxBellek: 268435456
    • getMemoryClass: 64

Ve (tencent'in yorumları başına):

  • LG Nexus 5 (4.4.3) normal
    • maxBellek: 201326592
    • getMemoryClass: 192
  • LG Nexus 5 (4.4.3) büyük yığın
    • maxBellek: 536870912
    • getMemoryClass: 192
  • Galaxy Nexus (4.3) normal
    • maxBellek: 100663296
    • getMemoryClass: 96
  • Galaxy Nexus (4.3) büyük yığın
    • maxBellek: 268435456
    • getMemoryClass: 96
  • Galaxy S4 Play Store Sürümü (4.4.2) normal
    • maxBellek: 201326592
    • getMemoryClass: 192
  • Galaxy S4 Play Store Edition (4.4.2) büyük yığın
    • maxBellek: 536870912
    • getMemoryClass: 192

Diğer cihazlar

  • Huawei Nexus 6P (6.0.1) normal
    • maxBellek: 201326592
    • getMemoryClass: 192

Özel android kullanarak bu iki yöntemi test etmedim: honeycomb'dan beri mevcut olan largeHeap = "true" manifest seçeneği, ancak cmcromance ve tencent sayesinde, yukarıda bildirildiği gibi bazı örnek largeHeap değerlerine sahibiz.

Benim beklenti (yukarıda largeHeap sayılarla desteklediği gibi görünüyor) bu seçenek bir köklü OS aracılığıyla manuel yığın ayarlamaya benzer bir etkiye sahip olacağını olurdu - yani o değerini artıracaktır maxMemory()terk ederken getMemoryClass()yalnız. LargeHeap ayarını kullanan bir uygulama için ne kadar belleğe izin verildiğini gösteren başka bir yöntem olan getLargeMemoryClass () vardır. GetLargeMemoryClass () belgeleri, "çoğu uygulamanın bu miktarda belleğe ihtiyacı olmaması ve bunun yerine getMemoryClass () sınırına uyması gerektiğini" belirtir.

Doğru tahmin edersem, bu seçeneği kullanmak, yığını köklü bir işletim sistemi aracılığıyla yükselten bir kullanıcı tarafından sağlanan alanı kullanmakla aynı faydalara (ve tehlikelere) sahip olurdu (yani, uygulamanız ek belleği kullanıyorsa, muhtemelen kullanıcının aynı anda çalıştırdığı diğer uygulamalarla çok iyi oynamaz).

Bellek sınıfının görünüşte 8MB'ın katları olması gerekmediğini unutmayın.

Yukarıdan, getMemoryClass()belirli bir aygıt / işletim sistemi yapılandırması için sonucun değişmediğini, yığın kullanıcı tarafından farklı ayarlandığında maxMemory () değeri değiştiğini görebiliriz.

Benim pratik deneyimim, G1'de (16 bellek sınıfı olan), yığın boyutu olarak 24MB'yi manuel olarak seçersem, bellek kullanımımın 20MB'a kadar kaymasına izin verilse bile hatasız çalışabilirim (muhtemelen Ben bunu denemedim rağmen 24MB kadar yüksek gitmek). Ancak benzer şekilde büyük olan diğer uygulamalar, kendi uygulamamın domuzcukluğunun bir sonucu olarak bellekten temizlenebilir. Ve tersine, benim bu diğer yüksek bakım uygulamaları kullanıcı tarafından ön plana çıkarılacağını eğer uygulama bellekten kızardı alabilirsiniz.

Bu nedenle, tarafından belirtilen bellek miktarını aşamazsınız maxMemory(). Ve, gereken denemek tarafından belirtilen sınırlar içinde kalmak getMemoryClass(). Bunu yapmanın bir yolu, eğer hepsi başarısız olursa, bu tür cihazların işlevselliğini belleği koruyacak şekilde sınırlamak olabilir.

Son olarak, belirtilen megabayt sayısını aşmayı planlıyorsanız getMemoryClass(), tavsiyem, uygulamanızın durumunun kaydedilmesi ve geri yüklenmesi üzerinde uzun ve sıkı çalışmaktır, böylece bir onStop()/ onResume()döngüsü gerçekleşirse kullanıcının deneyimi neredeyse kesintisiz olur .

Benim durumumda, performans nedenleriyle, uygulamamı 2.2 ve üzeri sürümleri çalıştıran cihazlarla sınırlandırıyorum ve bu, uygulamamı çalıştıran neredeyse tüm cihazların 24 veya daha yüksek bir bellek sınıfına sahip olacağı anlamına geliyor. Bu yüzden 20 MB'a kadar yığın kaplayacak şekilde tasarlayabilirim ve uygulamamın kullanıcının aynı anda çalıştırdığı diğer uygulamalarla iyi oynayacağından emin olabilirim.

Ancak her zaman eski bir cihaza (ör. Bir G1) 2.2 veya daha yüksek bir Android sürümü yükleyen birkaç köklü kullanıcı olacaktır. Böyle bir konfigürasyonla karşılaştığınızda, ideal olarak, hedeflemeniz gerektiğini söyleyen maxMemory()16MB'den çok daha yüksek bir seviyeye gidebileceğinizi söylese bile, bellek kullanımınızı azaltmanız gerekir . Uygulamanızın bu bütçe dahilinde yaşayacağından emin olamazsanız, en azından / öğesinin sorunsuz bir şekilde çalıştığından emin olun .getMemoryClass()onStop()onResume()

getMemoryClass(), yukarıda Diane Hackborn (hackbod) tarafından belirtildiği gibi, yalnızca API düzey 5'e (Android 2.0) geri döndüğünden, önerdiği gibi, işletim sisteminin önceki bir sürümünü çalıştıran herhangi bir cihazın fiziksel donanımının tasarlandığını varsayabilirsiniz. en fazla 16 MB alan kaplayan uygulamaları en iyi şekilde desteklemek için.

Buna karşılık, maxMemory(), belgelere göre, API düzeyinde 1. dönebildiyse kullanılabilir maxMemory()öncesi 2,0 versiyonunda, muhtemelen bir 16MB değer döndürmek ama olacak do my (çok sonraları) CyanogenMod sürümlerinde kullanıcı içinde olduğunu görüyoruz muhtemelen daha düşük bir yığın sınırı ile sonuçlanacak olan 12MB kadar düşük bir yığın değeri seçebilir ve bu nedenle maxMemory(), 2.0'dan önceki işletim sistemi sürümleri için bile değeri test etmeye devam etmenizi öneririm . maxMemory()Belirtilenden daha fazlasına izin vermeniz gerekiyorsa, bu değerin 16 MB'den daha düşük bir değere ayarlanması durumunda, reddetmeyi bile gerekebilir .


2
@Carl Merhaba Carl, Harika gönderi için teşekkürler. Ve seçeneği test ettim, android: largeHeap = "true" Galaxy S3 ile JellyBean'da. İşte sonuç. [maxMemory: 256.0MB, memoryClass: 64MB] (maxMemory, büyük yığın seçeneği olmadan 64MB idi)
cmcromance

1
@Carl Haha Büyük bir onur! :)
cmcromance

1
HTC One X için: maxMemory: 67108864 memoryClass: 64
Kishore

1
LG Nexus 5 (4.4.3) (normal): maxBellek: 201326592, bellek Sınıf: 192 | LG Nexus 5 (4.4.3) (büyük yığın): maxMemory: 536870912, bellek Sınıf: 192
ian.shaun.thomas

1
Çok güzel belgelenmiş. Lütfen bunu android'e sağlayın. Böyle uygun bir Android belgesi bulamıyorum
Jimit Patel

20

Resmi API :

Bu, daha büyük bellek aygıtlarının göründüğü 2.0'da tanıtıldı. İşletim sisteminin önceki sürümlerini çalıştıran cihazların orijinal bellek sınıfını kullandığını varsayabilirsiniz (16).


13

Debug.getNativeHeapSize()hile yapacak, düşünmeliyim. Yine de 1.0'dan beri orada.

DebugSınıf izleme tahsisleri ve diğer performans kaygıları için büyük bir çok metod. Ayrıca, düşük bellek durumu tespit etmeniz gerekiyorsa, kontrol edin Activity.onLowMemory().


Teşekkürler Neil. Uygulama, hata ayıklama kapalıyken çalışıyor mu?
hpique

2
Ben bu konuda oldukça yeniyim, ama yerel öbek sorununun başvurduğu uygulama (Dalvik) öbek ile aynı olduğunu düşünmüyorum. Yerel yığın, yerel kodla ayrılan bitmap verileri için destek sağlarken, uygulama yığını Java uygulama verilerini tutar. Yerel yığının uygulama yığınının sınırına sayıldığını öğrenmek ilgimi çekti ve 3.0'dan sonra tahsisler aslında uygulamanın yığınında gerçekleşiyor. Diane Hackborn (hackbod) burada bu konuda yayınlar: stackoverflow.com/questions/1945142/bitmaps-in-android Ancak 3.0 için bile, uygulama yığınında "yerel" olmayan veriler de var.
Carl

1
Bazı yeni Android güncellemelerinden (belki KitKat 4.4) beri bitmapler JVM yığınındadır.
akauppi

13

Bunu nasıl yapacağınız aşağıda açıklanmıştır:

Uygulamanın kullanabileceği maksimum yığın boyutunu elde etme:

Runtime runtime = Runtime.getRuntime();
long maxMemory=runtime.maxMemory();

Uygulamanızın şu anda ne kadar yığın kullandığını öğrenmek:

long usedMemory=runtime.totalMemory() - runtime.freeMemory();

Uygulamanızın artık ne kadar yığın kullanabileceğini öğrenmek (kullanılabilir bellek):

long availableMemory=maxMemory-usedMemory;

Ve her birini güzelce biçimlendirmek için şunları kullanabilirsiniz:

String formattedMemorySize=Formatter.formatShortFileSize(context,memorySize); 

5

Bu, bayt cinsinden maksimum yığın boyutu döndürür:

Runtime.getRuntime().maxMemory()

ActivityManager.getMemoryClass () kullanıyordum ama CyanogenMod 7'de (başka bir yerde test etmedim) kullanıcı yığın boyutunu manuel olarak ayarlarsa yanlış değer döndürür.


Çünkü doc getMemoryClass, sayının vm'niz için kullanılabilir yığın boyutuyla aynı olmayabileceği anlamına geldiğinden ve for getNativeHeapSize... taciturn olduğundan, gerçekten Runtime.getRuntime().maxMemory()en iyi cevap olduğunu düşünüyorum .
YK

3

Bazı işlemler java yığın alanı yöneticisinden daha hızlıdır. İşlemleri bir süre geciktirmek bellekte yer açabilir. Öbek boyutu hatasından kaçmak için bu yöntemi kullanabilirsiniz:

waitForGarbageCollector(new Runnable() {
  @Override
  public void run() {

    // Your operations.
  }
});

/**
 * Measure used memory and give garbage collector time to free up some
 * space.
 *
 * @param callback Callback operations to be done when memory is free.
 */
public static void waitForGarbageCollector(final Runnable callback) {

  Runtime runtime;
  long maxMemory;
  long usedMemory;
  double availableMemoryPercentage = 1.0;
  final double MIN_AVAILABLE_MEMORY_PERCENTAGE = 0.1;
  final int DELAY_TIME = 5 * 1000;

  runtime =
    Runtime.getRuntime();

  maxMemory =
    runtime.maxMemory();

  usedMemory =
    runtime.totalMemory() -
    runtime.freeMemory();

  availableMemoryPercentage =
    1 -
    (double) usedMemory /
    maxMemory;

  if (availableMemoryPercentage < MIN_AVAILABLE_MEMORY_PERCENTAGE) {

    try {
      Thread.sleep(DELAY_TIME);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }

    waitForGarbageCollector(
      callback);
  } else {

    // Memory resources are availavle, go to next operation:

    callback.run();
  }
}

test edilmiş İyi. Bu iki şeyi ayrıntılandırabilir misiniz: availableMemoryPerprint ve MIN_AVAILABLE_MEMORY_PERCENTAGE? bazı açıklamalar?
Noor Hossain

1
AvailableMemoryPercentageşu formüle göre: şu anda cihazın belleğinin ne kadar boş olduğu. MIN_AVAILABLE_MEMORY_PERCENTAGEözel parametreniz, çöp toplayıcısının işini yapmasını beklemeye başladığınız bir eşiktir.
Zon

1

Asus Nexus 7 (2013) 32Gig: getMemoryClass () = 192 maxMemory () = 201326592

Nexus 7'de oyunumu prototipleme hatasını yaptım ve ardından eşimin genel 4.04 tabletinde neredeyse anında bellek bittiğini keşfettim (memoryclass 48, maxmemory 50331648)

Bellek sınıfının düşük olduğunu belirlediğimde, daha az kaynak yüklemek için projemi yeniden yapılandırmam gerekecek.
Java'da geçerli yığın boyutunu görmenin bir yolu var mı? (Hata ayıklama sırasında logCat'te açıkça görebiliyorum, ancak geçerli yığın> (maxmemory / 2) yüksek kaliteli bitmap'leri düşük kalitede yüklüyormuş gibi uyarlamak için kodda görmek için bir yol istiyorum


Bahsedilen Nexus7-2013, getLargeMemoryClass () = 512.
akauppi

0

Programlı olarak mı, yoksa sadece geliştirip hata ayıklarken mi kastediyorsunuz? İkincisi ise, bu bilgiyi Eclipse'deki DDMS perspektifinden görebilirsiniz. Öykünücünüz (muhtemelen takılı fiziksel telefon bile) çalışırken, soldaki pencerede etkin işlemleri listeler. Bunu seçebilirsiniz ve yığın tahsislerini izleme seçeneği vardır.


Programlı olarak kastediyorum. Soruyu açıklığa kavuşturdu. Teşekkürler.
hpique

1
Bu gönderiye Android platform programcılarından biri tarafından bakmanızı öneririz: stackoverflow.com/questions/2298208/…
Steve Haley

0
Runtime rt = Runtime.getRuntime();
rt.maxMemory()

değer b

ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
am.getMemoryClass()

değer MB


Ne tür rt? Nerede ilan edilir?
FindOut_Quran
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.