【发布时间】:2011-11-23 23:34:10
【问题描述】:
我的应用程序遇到内存不足错误。我相当肯定我在某处泄漏了内存,并且我相信我已将其范围缩小到特定的 Activity,并且相信泄漏与 AdMob 有关。
为了说明我所看到的,如果启动我的应用程序,第一个活动占用大约 3Mb(它显示图像)。当第二个活动被加载时,第一个没有被销毁,总堆使用量增加到 ~ 7.8Mb。在第二个活动中加载 AdMob 广告后,总堆大小约为 12.5 Mb。
如果我通过按返回按钮返回第一个活动,则会调用第二个活动的onDestroy() 方法。但是,我的应用程序使用的内存量并没有减少。即使我明确调用 System.gc() 。我可能错了,但堆的数量不应该回到 3Mb 吗?
更让我困惑的是,如果我保持应用程序处于活动状态并再次打开第二个活动,那么每次返回和第四次时,堆大小可能只会增加 500kb 左右。就好像某些东西在第二个 Activity 中保持活跃并被重用,即使该 Activity 已被销毁。
我在这里简化了我的代码,看看是否有人可以告诉我我做错了什么。我还使用 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>
【问题讨论】:
-
阅读
System.gc()的文档。它不是“现在就做”,更像是“如果你现在就做就好了,如果不是我道歉” -
谢谢,但我相当肯定 GC 会在某个时候被调用。特别是如果我多次重新启动活动并且堆大小不断增加
-
它当然会运行,但是没有定义GC会在你调用
gc()时立即运行。引用:There is no guarantee that the garbage collector will actually be run. -
嗯.. 当
onDestroy被调用时,你是recycling你的位图吗?如果我没记错的话,位图的处理方式是垃圾收集器无法释放它们使用的内存 -
我自己并没有回收位图,但我认为这不是问题所在。我又弄乱了 MAT 并发现了以下内容。如果我有关于我的第二个活动的广告,当回到第一个活动时,我的第二个活动会保留在内存中。没有广告,第二个 Activity 被正确销毁。问题出在广告上,我一定没有正确销毁它。
标签: android memory-leaks