Bellek / kaynak sızıntılarını bulmak için hangi Android araçları ve yöntemleri en iyi sonucu verir? [kapalı]


152

Geliştirilmiş bir Android uygulamam var ve her şeyin iyi çalıştığı ve zafer ve gemi beyan etmek istediğiniz bir telefon uygulaması geliştirme noktasındayım, ancak bazı bellek ve kaynak sızıntıları olması gerektiğini biliyorsunuz Orada; ve Android'de sadece 16mb yığın var ve bir Android uygulamasına sızması şaşırtıcı derecede kolay.

Etrafa baktım ve şimdiye kadar sadece 'hprof' ve 'traceview' hakkında bilgi kazmayı başardık ve ne de çok olumlu eleştiriler alıyor.

Hangi işletim sistemiyle karşılaştığınız veya geliştirdiğiniz ve paylaşmaya özen gösterdiğiniz araçlar veya yöntemler nelerdir?


3
Р̀СТȢѸ́ФХѾЦЧШЩЪЫЬѢѤЮѦѪѨѬѠѺѮѰѲѴ adını okunabilir bir şeyle değiştirmek için oy kullanabilir miyim?
JPM

1
"Android Araçları" kelimesini soru başlığından kaldırırsak bu soruyu yeniden açmak uygun olur mu? Burada bulunan cevaplar, bellek sızıntısı sorunlarımı çözmek için oldukça kullanışlıdır
k3b

Tamam, yani sürekli aktiviteler arasında geçiş yapan bir kullanıcı var, yani 20 saniyede 15 aktiviteyi değiştirmiş olabilirler. Bu, yetersiz bellek hatasının nedeni olabilir mi? Düzeltmek için ne yapmalıyım? Teşekkürler!
Ruchir Baronia

1
Soru kapatıldığı için bunu yanıt olarak veremem, ancak Sızıntı Kanarya'ya göz atmanızı tavsiye ederim . Uygulamanızı kullanın, etkinlikleri açın ve kapatın ve kütüphanenin işini yapmasına izin verin. Hatta size sızıntının nerede meydana geldiğini bile söyleyecektir. Sızıntı analizörüne sızıntı oluştuktan sonra işini yapması için biraz zaman verin - sızıntının kaynağı bulunana kadar yaklaşık 2 dakika veya daha fazla zaman alır. Bundan sonra size düzgün bir şekilde uygulama içi sunacaktır. Ekstra alet gerekmez!
Ubuntudroid

Yanıtlar:


90

Android Uygulamaları geliştirirken bulduğum en yaygın hatalardan biri “java.lang.OutOfMemoryError: Bitmap Boyutu VM Bütçesini Aşar” hatasıdır. Yönü değiştirdikten sonra çok sayıda bitmap kullanan etkinliklerde bu hatayı frecuently buldum: Etkinlik yok edildi, tekrar oluşturuldu ve düzenler, bitmapler için kullanılabilen VM belleğini tüketen XML'den “şişirildi”.

Önceki etkinlik düzenindeki bitmapler, etkinliklerine ilişkin referansları çaprazladıkları için çöp toplayıcı tarafından düzgün şekilde yerleştirilmez. Birçok deneyden sonra bu sorun için oldukça iyi bir çözüm buldum.

İlk olarak, XML düzeninizin üst görünümünde “id” özelliğini ayarlayın:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="fill_parent"
     android:layout_height="fill_parent"
     android:id="@+id/RootView"
     >
     ...

Ardından, Etkinliğinizin onDestroy () yönteminde, üst Görünüm'e bir başvuru ileterek unbindDrawables () yöntemini çağırın ve bir System.gc () işlemi yapın

@Override
protected void onDestroy() {
    super.onDestroy();

    unbindDrawables(findViewById(R.id.RootView));
    System.gc();
}


private void unbindDrawables(View view) {

    if (view.getBackground() != null) {
        view.getBackground().setCallback(null);
    }

    if (view instanceof ViewGroup) {
        for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
            unbindDrawables(((ViewGroup) view).getChildAt(i));
        }

        ((ViewGroup) view).removeAllViews();
    }
}

Bu unbindDrawables () yöntemi, görünüm ağacını özyinelemeli olarak inceler ve:

  1. Tüm arka plan çekilebilir araçlarındaki geri çağrıları kaldırır
  2. Her görünüm grubundaki alt öğeleri kaldırır

3
Ortak bir soruna iyi bir çözüm.
While-E

9
AdapterView (ListView, GridView vb.) Alt sınıfları için çalışmaz.
Arjun

@Arjun Yes..it, AdapterView alt sınıfları için çalışmaz. Bunun için istisnayı ele almanız gerekir. Dinlenme iyi çalışıyor. Kodumda kullandığım bu ve iyi çalışıyor. Bu yardımcı olur umarım.
hp.android

@ hp.android "İstisnada bunu ele al" ifadesine göre, bunun nasıl görüneceğine dair bir örneğiniz var mı? Soruyorum çünkü resimlerimde sayfalar var PageAdapterve bu hatayla çalışıyorum :(
Jacksonkr

4
@Jackson sadece koşulu değiştirirse: (ViewGroup & instanceof görünümünü görüntüle &&! (AdapterView instanceof görüntüle)) Bu, Adaptör için aldığınız istisnadan kurtulur
hp.android


28

Çoğunlukla gelecekten gelen Google gezginleri için:

Çoğu java aracı maalesef bu görev için uygun değildir, çünkü sadece JVM-Heap'i analiz ederler. Her Android Uygulamasının da yerel bir yığın vardır, ancak ~ 16 MB sınırına uyması gerekir. Genellikle bitmap verileri için kullanılır. Bu nedenle, JVM-Heap'iniz 3 MB civarında soğutulsa bile, çok fazla çekilebilir cihaz kullanıyorsanız, Bellek Yetersiz hatalarına kolayca girebilirsiniz.


6
başlangıç ​​Android 3.0 (petek)
çekmeceleri

@Timo, yerel yığındaki sızıntıları tespit etmek için ne kullanırdınız?
sydd

1
Test, çok fazla test. Sorun, bellek paylaşımı ve diğer optimizasyon teknikleri nedeniyle uygulamanızın ne kadar bellek kullandığını gerçekten söyleyememenizdir. Her zamanki kabuk komutlarını kullanarak bellek okumaları alabilirsiniz, ancak bunlar çok, çok kaba tahminlerdir.
Timo Ohr

20

@ Hp.android'in yanıtı, sadece bitmap arka planları ile çalışıyorsanız, ancak benim durumumda, bir BaseAdapteriçin bir dizi ImageViews sağladım GridView. Değiştirilmiş unbindDrawables()durumdur böylece tavsiye olarak yöntemini:

if (view instanceof ViewGroup && !(view instanceof AdapterView)) {
  ...
}

fakat o zaman sorun, özyinelemeli yöntemin asla çocuklarını işlememesi AdapterView. Bunu ele almak için aşağıdakileri yaptım:

if (view instanceof ViewGroup) {
  ViewGroup viewGroup = (ViewGroup) view;
  for (int i = 0; i < viewGroup.getChildCount(); i++)
    unbindDrawables(viewGroup.getChildAt(i));

  if (!(view instanceof AdapterView))
    viewGroup.removeAllViews();
}

böylece çocukları AdapterViewhala işlenir - yöntem sadece (desteklenmeyen) tüm çocukları kaldırmaya çalışmaz.

Ancak bu ImageViewonların arka planı olmayan bir bitmap yönettiği için bu sorunu tam olarak çözmez . Bu nedenle aşağıdakileri ekledim. İdeal değil ama işe yarıyor:

if (view instanceof ImageView) {
  ImageView imageView = (ImageView) view;
  imageView.setImageBitmap(null);
}

Genel olarak unbindDrawables()yöntem şu şekildedir:

private void unbindDrawables(View view) {
  if (view.getBackground() != null)
    view.getBackground().setCallback(null);

  if (view instanceof ImageView) {
    ImageView imageView = (ImageView) view;
    imageView.setImageBitmap(null);
  } else if (view instanceof ViewGroup) {
    ViewGroup viewGroup = (ViewGroup) view;
    for (int i = 0; i < viewGroup.getChildCount(); i++)
    unbindDrawables(viewGroup.getChildAt(i));

    if (!(view instanceof AdapterView))
      viewGroup.removeAllViews();
  }
}

Bu tür kaynakları boşaltmak için daha ilkeli bir yaklaşım olmasını umuyorum.


12

Android'de Bellek Yönetimi hakkında iyi Google I / O konuşması (2011) ve bellek profili oluşturma için araçlar + teknikler hakkında ayrıntılar:
http://www.youtube.com/watch?v=_CruQY55HOk



1
Tamam, yani sürekli aktiviteler arasında geçiş yapan bir kullanıcı var, yani 20 saniyede 15 aktiviteyi değiştirmiş olabilirler. Bu, yetersiz bellek hatasının nedeni olabilir mi? Düzeltmek için ne yapmalıyım? Teşekkürler!'
Ruchir Baronia


1

Peki, bunlar Android'in kullandığı benzersiz biçimlerle bağlanan araçlardır.

Android Mock Framework'ü kullanarak sahte kod test alanlarını denediniz mi?


1
çok fazla değil, bu doğanın test edilmesi, uygulama çalışırken gerçekte ne olduğunu kaydetmek kadar sorun değil, gerçekten ihtiyacım olan bir kaynak / bellek sızıntısı profil oluşturma aracı
jottos
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.