Bir Android uygulaması için kullanılabilir uygulama yığını boyutunu program aracılığıyla nasıl tespit edersiniz?
SDK'nın sonraki sürümlerinde bunu yapan bir işlev olduğunu duydum. Her durumda, 1.5 ve üstü için çalışan bir çözüm arıyorum.
Bir Android uygulaması için kullanılabilir uygulama yığını boyutunu program aracılığıyla nasıl tespit edersiniz?
SDK'nın sonraki sürümlerinde bunu yapan bir işlev olduğunu duydum. Her durumda, 1.5 ve üstü için çalışan bir çözüm arıyorum.
Yanıtlar:
"Uygulama yığını boyutu kullanılabilir" ifadenizi düşünmenin iki yolu vardır:
Zor bir hata tetiklenmeden önce uygulamam ne kadar yığın kullanabilir? Ve
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:
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:
Ayrıca (aşağıdaki bir yorumda Kishore başına):
Ve (akauppi'nin yorumu uyarınca):
Cmcromance'den bir yorum başına:
Ve (tencent'in yorumları başına):
Diğer cihazlar
Ö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 .
Debug.getNativeHeapSize()
hile yapacak, düşünmeliyim. Yine de 1.0'dan beri orada.
Debug
Sı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()
.
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);
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.
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 .
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();
}
}
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.
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
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.
Runtime rt = Runtime.getRuntime();
rt.maxMemory()
değer b
ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
am.getMemoryClass()
değer MB
rt
? Nerede ilan edilir?