Android'de çöp toplayıcı


108

Bazı durumlarda çöp toplayıcıyı çağırmayı öneren birçok Android cevabı gördüm.

Hafızaya aç bir işlem yapmadan önce Android'de çöp toplayıcıyı istemek iyi bir uygulama mı? Değilse, sadece bir OutOfMemoryhata alırsam aramalı mıyım ?

Çöp toplayıcıya başvurmadan önce kullanmam gereken başka şeyler var mı?

Yanıtlar:


144

Bal peteği 3.0'dan önceki sürümler için : Evet, arayın System.gc() .

Bitmapler oluşturmaya çalıştım, ancak her zaman "VM yetersiz bellek hatası" alıyordum. Ama System.gc()ilk aradığımda sorun yoktu.

Bitmapler oluştururken, Android genellikle yetersiz bellek hatalarıyla başarısız olur ve önce çöp toplamaya çalışmaz . Bu nedenle, arayın System.gc()ve Bitmapler oluşturmak için yeterli belleğiniz var.

Nesneler oluşturuyorsanız, System.gcgerektiğinde otomatik olarak çağrılacağını düşünüyorum , ancak bitmap oluşturmak için değil . Sadece başarısız olur.

Bu yüzden System.gc()bitmapler oluşturmadan önce manuel olarak çağırmanızı tavsiye ederim .


39
Bunun nedeni, petek öncesi bitmap verilerinin VM'de depolanmaması ve dolayısıyla GC'yi tetiklememesidir. Honeycomb ve sonrasında sorun olmamalı.
Timmmm

2
@Timmmm ama aslında benim sorunumdu, sadece bigheap'i true olarak ayarladım.
Lei Leyba

118

Genel olarak konuşursak, bir çöp toplayıcının varlığında , GC'yi manuel olarak çağırmak asla iyi bir uygulama değildir. Bir GC, kendi cihazlarına bırakıldığında en iyi şekilde çalışan sezgisel algoritmalar etrafında düzenlenmiştir. GC'yi manuel olarak aramak genellikle performansı düşürür.

Nadiren , bazı nispeten nadir durumlarda, kişi belirli bir GC'nin yanlış anladığını görebilir ve GC'ye yapılan manuel bir çağrı, performans açısından işleri iyileştirebilir. Bunun nedeni, belleği her durumda en iyi şekilde yönetecek "mükemmel" bir GC'nin uygulanmasının gerçekten mümkün olmamasıdır. Bu tür durumları tahmin etmek zordur ve pek çok ince uygulama detayına bağlıdır. "İyi uygulama" GC'nin kendi başına çalışmasına izin vermektir; Genel Kurul'a manuel bir çağrı, ancak gerçek bir performans sorununa usulüne uygun olarak tanık olduktan sonra tasavvur edilmesi gereken bir istisnadır.


8
Platformdan bağımsız iyi bir cevap için +1. Seçim yapmadan önce birinin Android'e özel bir cevap bulup bulmadığını görmek için bekliyorum.
hpique

8
Ne yazdığını katılıyorum eğer sen CPU verimliliği daha genel ortalama bir şeye "performans" izin verir. Bir Android cihazda, kullanıcının performans algısı çok önemlidir. Geliştirici, örneğin kullanıcı düğmelere basarken GC'yi çalıştırmayı tercih edebilir, böylece kullanıcı GC'den haberdar olmayacaktır.
Başkan James K. Polk

5
Oyunlarda genellikle GC'nin oyun çalışırken çalışmaması önemlidir (bu, tüm nesnelerin önceden oluşturulmasını ve geri dönüştürülmesini veya benzerini gerektirir), ancak oyun duraklatıldığında GC için iyi bir zamandır.
Pat

4
Petek öncesi, bit eşlem verileri VM belleğinde depolanmaz. Bit eşlemler nedeniyle çok fazla VM olmayan bellek kullandığınızda sistem algılamaz ve GC'yi çalıştırır (bu, Bitmap.finalize()VM olmayan belleği serbest bırakan yöntemleri çalıştırır ). Bu nedenle, bu durumda, GC'nin başının üzerinden geçmeli ve koşmalı Bitmap.recycle()veya System.gc()uygunsa. Ama sadece bal peteği öncesi.
Timmmm

1
@ThomasPornin - Öte yandan, bir uygulama programcısı olarak, işletim sisteminin bilmediği bir şey biliyorsunuz: uygulamanızın artık belleği kullanma biçiminde büyük bir değişiklik yapacağı ve daha az rahatsız edici olacağı zamanlar kullanıcı deneyimi gelecekte keyfi bir zaman yerine şimdi duraklama . Bu , uygulamanın nasıl kullanıldığı ile ilgili büyük geçişlerde seyrek aramalar yapmanın mantıklı olabileceği anlamına gelir . Bunlar nadir bir sık GC çağırarak gerektiğini anlamda, ama olan ortak olduğu herhangi önemli bir app vardır böyle bilinen-by-tasarım anlar içinde.
ToolmakerSteve

26

Android uygulamasında yetersiz bellek, bitmap'i düzgün bir şekilde kullanmazsak çok yaygındır, sorunun çözümü

if(imageBitmap != null) {
    imageBitmap.recycle();
    imageBitmap = null;
}
System.gc();
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 3;
imageBitmap = BitmapFactory.decodeFile(URI, options);
Bitmap  scaledBitmap = Bitmap.createScaledBitmap(imageBitmap, 200, 200, true);
imageView.setImageBitmap(scaledBitmap);

Yukarıdaki kodda Bitmap'i geri dönüştürmeyi denedim, bu da kullanılan bellek alanını boşaltmanıza izin verecek, bu nedenle bellek yetersiz olabilir.

Hala sorunla karşı karşıyaysanız, bu satırı da ekleyebilirsiniz.

BitmapFactory.Options options = new BitmapFactory.Options();
options.inTempStorage = new byte[16*1024];
options.inPurgeable = true;

daha fazla bilgi için bu bağlantıya bir göz atın

https://web.archive.org/web/20140514092802/http://voices.yahoo.com/android-virtual-machine-vm-out-memory-error-7342266.html?cat=59


NOT: nedeniyle gc gerçekleştirerek kaynaklanan anlık "duraklama" için, bu olup değil önce bunu tavsiye her bitmap tahsisi.

Optimum tasarım:

  1. Free artık gerekli olmayan tüm bitmapler tarafından, if / recycle / nullgösterilen kod. (Buna yardımcı olacak bir yöntem yapın.)

  2. System.gc();

  3. Yeni bit eşlemleri ayırın.


19

Bir OutOfMemoryError alırsanız, çöp toplayıcıyı aramak için genellikle çok geç demektir ...

İşte Android Geliştiricisinden alıntı:

Çoğu zaman, çöp toplama, tonlarca küçük, kısa ömürlü nesneler nedeniyle oluşur ve kuşak çöp toplayıcıları gibi bazı çöp toplayıcılar, uygulamanın çok sık kesintiye uğramaması için bu nesnelerin toplanmasını optimize edebilir. Android çöp toplayıcı ne yazık ki bu tür optimizasyonları gerçekleştiremiyor ve performans açısından kritik kod yollarında kısa ömürlü nesnelerin oluşturulması bu nedenle uygulamanız için çok maliyetli.

Anladığım kadarıyla, gc'yi aramaya acilen gerek yok. Gereksiz nesnelerin yaratılmasından kaçınmak için daha fazla çaba harcamak daha iyidir (döngülerin içinde nesnelerin oluşturulması gibi)


6
Alıntı başka bir şekilde yorumlanamaz mı? Belki de bu nesneleri çok fazla bellek tüketmeden önce toplamak için GC'nin manuel olarak çağrılması gerekir.
hpique

@hgpc: Alıntının önerdiğiniz şekilde nasıl yorumlanabileceğini anlamıyorum. Belgelerin bir itiraf olduğunu tahmin ediyorum, GC'lerinin basit olduğunu kabul ediyorum; bellek azaldığında, dolu bir GC yürütülür.
Başkan James K. Polk

Karmaşık nesnelerden ve karmaşık nesneler kullanan çerçevelerden tam olarak yararlanmak, geliştirme süresini erken optimizasyona göre daha iyi kullanma eğilimindedir. Optimizasyon konusunda endişelenmek, bir mobil uygulamayı kodlarken bilinçsizce performans hakkında düşünmeye devam ettiğimizden, Android için Kurumsal Java'ya göre daha kolay bir tuzaktır. Özellikle performans hakkında düşünmesi gereken çerçeve geliştiricileri, dikkatli olmadıklarında bu bakış açısını resmi belgelerine sızdırırlar.
LateralFractal

9

System.gc()Art Android 6.0.1 Nexus 5x'te çalışmıyor gibi görünüyor , bu yüzden Runtime.getRuntime().gc();onun yerine kullanıyorum.


1
System.gc()için bir sarmalayıcı işlevidir Runtime.getRuntime().gc(). Android.googlesource.com/platform/libcore/+/… sayfasına
Nathan F.

Evet, kaynaktan ve dokümantasyondan aynı görünüyorlar, ama gerçekten System.gc()benim için çalışmıyor ama işe yarıyor Runtime.getRuntime().gc()!
Ivan

7

Uygulamam birçok görüntüyü yönetiyor ve bir OutOfMemoryError ile öldü. Bu bana yardımcı oldu. Manifest.xml'de Ekle

<application
....
   android:largeHeap="true"> 

9
Google bundan hoşlanmıyor
Pedro Paulo Amorim

1
@PedroPauloAmorim nedenini açıklıyor?
Machado

2
Ne yaptığınızdan emin değilseniz, largeHeap'i kullanmayın. Büyük yığınların kullanılması, Çöp toplayıcının belleği temizlemeden önce çok sayıda önemsiz veriyi dolaşması gerektiğinden çok daha fazla çalışmasını sağlar.
Prakash

7

Genel olarak konuşursak, GC'yi açıkça System.gc () ile çağırmamalısınız. GC duraklatma günlüğünün ne anlama geldiğini açıkladıkları ve Dalvik daha iyi bildiği için System.gc () 'yi asla çağırmamayı belirttikleri IO dersi ( http://www.youtube.com/watch?v=_CruQY55HOk ) bile var ne zaman yapacağınızdan daha fazla.

Öte yandan, yukarıda da belirtildiği gibi, zaten Android'deki GC işlemi (her şey gibi) bazen hatalı. Bu, Dalvik GC algoritmalarının Hotspot veya JRockit JVM'lerle aynı olmadığı ve bazı durumlarda işleri yanlış yapabileceği anlamına gelir. Bu durumlardan biri, bitmap nesnelerinin tahsis edilmesidir. Bu zor bir durumdur çünkü Heap ve Non Heap belleği kullanır ve bellek kısıtlamalı cihazdaki bir gevşek bitmap nesnesi örneği size bir OutOfMemory istisnası vermek için yeterlidir. Bu yüzden, artık bu bitmap'e ihtiyacınız kalmadığında çağırmak, genellikle birçok geliştirici tarafından önerilir ve hatta bazı insanlar tarafından iyi bir uygulama olarak kabul edilir.

Bitmap'in yerel belleğini silmek için güvenli olarak işaretlediği için, bu yöntemin amacı bu olduğundan .recycle () bir bitmap üzerinde daha iyi bir uygulamadır. Bunun sürüme bağlı olduğunu, yani genellikle eski Android sürümlerinde (sanırım Pre 3.0) gerekli olacağını, ancak daha sonraki sürümlerde gerekli olmayacağını unutmayın. Ayrıca daha yeni sürümler ether'i kullanmaktan da zarar gelmez (bunu bir döngüde veya benzeri bir şeyde yapmayın). Yeni ART çalışma zamanı burada çok değişti çünkü büyük nesneler için özel Yığın "bölme" oluşturdular, ancak bunu ART eter ile yapmanın pek bir zararı olmayacağını düşünüyorum.

Ayrıca System.gc () hakkında çok önemli bir not. Bu yöntem Dalvik'in (veya JVM'lerin) yanıt vermek zorunda olduğu bir komut değildir. Bunu daha çok Sanal makineye "Eğer bir güçlük değilse lütfen çöp toplama yapabilir misiniz" demek gibi düşünün.



3

Hayır derdim, çünkü Geliştirici RAM kullanım durumuyla ilgili belgeler :

...
GC_EXPLICIT

Gc () 'yi çağırdığınızda olduğu gibi açık bir GC (ki bunu çağırmaktan kaçınmanız ve bunun yerine gerektiğinde GC'nin çalışacağına güvenmeniz gerekir).

...

İlgili kısmı kalın olarak vurguladım.

YouTube serisine, Android Performans Modellerine bir göz atın - size uygulamanızın bellek kullanımını yönetme konusunda ipuçları gösterecektir (örneğin, s yerine Android’leri ArrayMapve ’ SparseArrayleri kullanma HashMap).


3

Xamarin geliştiricileri için hızlı not .

Aramak istiyorsanız System.gc()Xamarin.Android içinde aramak gerekir appsJava.Lang.JavaSystem.Gc()


2

Çöp toplayıcıyı bir OutOfMemoryError.

Javadoc açıkça belirtiyor:

Thrown when the Java Virtual Machine cannot allocate an object because it is out of memory, and no more memory could be made available by the garbage collector.

Dolayısıyla, çöp toplayıcı, hatayı oluşturmadan önce belleği boşaltmaya çalıştı ancak başarısız oldu.


8
Android Javadoc bunu belirtmiyor ve büyük olasılıkla uygulaması farklı. d.android.com/reference/java/lang/OutOfMemoryError.html
hpique

Bunun Android için geçerli olmadığı konusunda haklısınız. Ama yine de OOE'yi çalışma zamanı eterinde idare edemezsiniz, bu yüzden bu doğru olsa / olmasa bile bu konuda fazla bir şey yapamazsınız.
Igor Čordaš
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.