2013-06-19 20 views
16

Benim app bir bellek sızıntısı için bir av içinde anlayamıyorum bir davranış aşağı kovaladı. Ben büyük bir bellek bloğu ayırmak, ancak onDestroy açık başvuru null sürece, bir OOM ile sonuçlanan çöp toplanan almaz.Büyük bellek yığını değil çöp toplanan değil

Bu örnekte, birbirlerinin arasında geçiş yapan iki hemen hemen aynı aktivitem var. Her ikisinde de tek bir düğme var. MainActivity düğmesine basıldığında, OOMActivity ve OOMActivity, finish() öğesini çağırarak döner. Düğmelere birkaç kez bastıktan sonra, Android bir OOMException atar.

OnDestroy öğesini OOMActivity öğesine eklediysem ve açık bellek boşluğuna başvuruyu açık olarak eklerseniz, günlüğünde belleğin doğru şekilde boşaldığını görebilirim.

Neden bellek nulling olmadan otomatik olarak serbest kalmıyor?

MainActivity:

package com.example.oom; 

import android.app.Activity; 
import android.content.Intent; 
import android.os.Bundle; 
import android.view.View; 
import android.view.View.OnClickListener; 
import android.widget.Button; 

public class MainActivity extends Activity implements OnClickListener { 

    private int buttonId; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     System.gc(); 
     Button OOMButton = new Button(this); 
     OOMButton.setText("OOM"); 
     buttonId = OOMButton.getId(); 

     setContentView(OOMButton); 
     OOMButton.setOnClickListener(this); 
    } 

    @Override 
    public void onClick(View v) { 
     if (v.getId() == buttonId) { 
      Intent leakIntent = new Intent(this, OOMActivity.class); 
      startActivity(leakIntent); 
     } 
    } 

} 

OOMActivity: Bu durumda (sınıf OS anlamına gelmez Android'i görmüyorum sırf

public class OOMActivity extends Activity implements OnClickListener { 

    private static final int WASTE_SIZE = 20000000; 
    private byte[] waste; 
    private int buttonId; 

    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     Button BackButton = new Button(this); 
     BackButton.setText("Back"); 
     buttonId = BackButton.getId(); 

     setContentView(BackButton); 
     BackButton.setOnClickListener(this); 

     waste = new byte[WASTE_SIZE]; 

    } 

    public void onClick(View view) { 
     if (view.getId() == buttonId) { 
      finish(); 
     } 
    } 

} 
+0

harika bir örnek, harika bir soru! – WarrenFaith

+0

Lütfen bu sohbeti okuyun. Biz burada tartıştık (http://chat.stackoverflow.com/transcript/message/10084186#10084186) – Reno

+2

Muhtemelen bu ürünü bir ön bal peteği üzerinde deniyorsunuz. Post-petek üzerindeki çöp toplayıcı, "atık" nesnesini serbest bırakacak kadar agresif olacaktır. 4.1.2, 4.2.2, 2.3.5, 2.3.7'de test edilmiştir. "Waste = new byte [WASTE_SIZE]" önce System.gc() yöntemini çağırmak, ön bal peteği aygıtlarında sorun olmasını önler. – pellucide

cevap

1

Etkinlik imha, sınıf yıkımı anlamına gelmez) tüm referansları kaybetti ve bitirin. Bu nedenle, dokümanlarda bile, bellek sızıntılarını önlemek için gerek duyduğunuz tutamaçları ve nesneleri temizlemeyi belirttiklerinden. Şerefe.

1

birkaç nokta:

1) Sadece GC günlükleri izleyerek Etkinlik sızdırılmış ediliyor olsa da olmasa hakim olamaz; Her bir JVM uygulaması, herhangi bir şey referans göstermese bile, nesneleri toplayıp ne zaman toplanacağını seçmekte özgürdür. Bir OOM hatası vermeden önce çöp toplamasının gerekli olduğunu unutmayın ... ancak yeterli bellek varsa, etkinliklerinizin 10'unu bellekte tutmayı ve hepsini bir kerede toplamayı seçebilir. 2) Aktivitenize, Faaliyetin yaşam döngüsünden daha uzun bir süre devam eden dahili Android yapıları olabilir ... ve geliştiricinin bunun üzerinde hiçbir kontrolü yoktur. Bu nedenle, Faaliyetin herhangi bir büyük miktarda veriye referans vermemesi önerilir (ya da eğer varsa, bu referanslar onDestroy'da açık bir şekilde serbest bırakılmalıdır (ya da daha agresif olmak istiyorsanız).

3) Bazı JVM'ler çalışma zamanında optimize edilir, böylece hiç yazılmayan veya erişilmeyen bir bellek parçası asla fiziksel belleğe tahsis edilmez. Belki de bu nedenle, testiniz Android'in daha yeni sürümlerinde geçerli değildir. Bunu aşmak için, dizideki bazı değerleri rastgele değerler olarak ayarlayan bir döngü ekleyebilir ve ardından kodda okuyan başka bir döngü daha ekleyebilir; bu şekilde JVM belleği ayırmaya zorlanır.

İlgili konular