Android发现内存泄漏问题

时间:2011-11-23 23:34:10

标签: android memory-leaks

我的应用程序遇到内存不足错误时遇到问题。我很确定我在某个地方泄漏了记忆,我相信我已将其缩小到某个特定的活动,并认为泄漏与AdMob有关。

为了说明我所看到的,如果启动我的应用程序,第一个活动占用大约3Mb(它显示图像)。加载第二个活动时,第一个活动不会被销毁,总堆使用量会增加到〜7.8Mb。在第二个活动中加载AdMob广告后,总堆大小将达到大约12.5 Mb。

如果我通过按后退按钮返回第一个活动,则会调用第二个活动的onDestroy()方法。但是,我的应用程序使用的内存量根本不会减少。即使我明确地调用System.gc()。我可能错了,但堆的数量不应该回到3Mb吗?

让我更加困惑的是,如果我让应用程序保持活动状态并再次打开第二个活动,那么每次返回第四个时,堆大小只会增加500kb左右。即使活动已被破坏,就好像某些东西在第二个活动中被保存并重复使用。

我在这里简化了我的代码,看看有人能告诉我我做错了什么。我也看过使用MAT的转储文件但是我不太确定我正在看什么并且没有找到太多用处。

我的第一个(默认)活动

public class FirstActivity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, 
                             WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

        setContentView(R.layout.main);
     }


     public void startSelectionPage(View v){
         Intent intent = new Intent(FirstActivity.this, ImageSelectActivity.class);
         startActivity(intent);
     }
}

main.xml中

<?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:background="@drawable/startpage" >

        <ImageButton
          android:id="@+id/pb"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:background="@drawable/playbutton"
          android:onClick="startSelectionPage"          
     />
</RelativeLayout>

ImageSelectActivity

public class ImageSelectActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         requestWindowFeature(Window.FEATURE_NO_TITLE);
         getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, 
                             WindowManager.LayoutParams.FLAG_FULLSCREEN);

         setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

         setContentView(R.layout.selectionpage);    

         ((Gallery) findViewById(R.id.gallery))
         .setAdapter(new ImageAdapter(this.getApplicationContext(), 150));     
    }

     @Override
     public void onDestroy() {
        AdView ad = (AdView) findViewById(R.id.adView);
        ad.destroy();
        super.onDestroy();
     }
 }

 class ImageAdapter extends BaseAdapter {
    private Context myContext;
    private int imageBackground;
    private int galleryHeight;

    private int[] myImageIds = {
                R.drawable.canyonthumb,
                R.drawable.yosemitethumb,
                R.drawable.flowerthumb,
                R.drawable.squirrelthumb

    };

    public ImageAdapter(Context c, int galleryHeight) { 
        this.myContext = c;
        TypedArray ta = c.obtainStyledAttributes(R.styleable.GalleryTheme);
        imageBackground = ta.getResourceId(R.styleable.GalleryTheme_android_galleryItemBackground, 1);
        ta.recycle();
        this.galleryHeight = galleryHeight;
    }

    public int getCount() { return this.myImageIds.length; }
    public Object getItem(int position) { return position; }
    public long getItemId(int position) { return position; }

    public View getView(int position, View convertView, ViewGroup parent) {     
        ImageView imageView = new ImageView(myContext);
        imageView.setScaleType(ImageView.ScaleType.FIT_XY);
        imageView.setLayoutParams(new Gallery.LayoutParams(galleryHeight,galleryHeight));
        imageView.setBackgroundResource(imageBackground);
        imageView.setImageResource(this.myImageIds[position]);
        return imageView;
    }
}

selectionpage.xml     

        <ImageView
            android:id="@+id/imageView1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/chooseanimage"/>

        <RelativeLayout
            android:id="@+id/rlayout1"
              android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            >

                    <com.google.ads.AdView android:id="@+id/adView"
                         android:layout_width="wrap_content"
                         android:layout_height="60dp"
                         ads:adUnitId="----"
                         ads:adSize="IAB_BANNER"
                         ads:testDevices="TEST_EMULATOR,---"
                         ads:loadAdOnCreate="true"
                         />

                    <Gallery
                        android:id="@+id/gallery"
                        android:layout_width="fill_parent"
                        android:layout_height="fill_parent"
                        android:layout_below="@id/imageView1"
                        android:layout_above="@+id/adView"
                        />

        </RelativeLayout>   
        </LinearLayout>        

3 个答案:

答案 0 :(得分:0)

查看此问题:android memory management in activity lifecycle。它与您的问题不完全相同,但答案中包含我认为您正在寻找的信息。

所以不要再输入关于内存,垃圾收集器和活动生命周期之间关系的长解释,我将引用您的上述问题。

答案 1 :(得分:0)

我不确定我的代码是否正确,但我认为这是:

ImageSelectActivity中,您可以创建ImageAdapter的新对象。当您在new调用中使用setAdapter()时,它是一个匿名对象。

只要您的活动存在,ImageAdapter对象就不会被销毁。您可以在onDestroy()

中将您的活动适配器设置为null

一篇非常好的博客文章是关于您的主题:avoiding memory leaks

最后的第三点:

  

如果您不控制,请避免活动中的非静态内部类   他们的生命周期,使用静态内部类并做出弱引用   到里面的活动。这个问题的解决方案是使用静态   内部类与外部类的WeakReference,如在中所做的那样   例如ViewRoot及其W内部类

这就是你应该做的事情。

答案 2 :(得分:0)

我不相信我曾经有过内存泄漏。问题在于GC,它似乎允许对象在内存中保留的时间比我预期的要长得多。如果我在16Mb仿真器上尝试代码,那么GC可以更加积极地工作。

我没想到的另一件事是AdMob的高内存使用率。将广告添加到我的一个活动中导致使用大约8MB的堆。