Android:AlertDialog导致内存泄漏

时间:2011-08-16 18:51:03

标签: android memory-leaks alertdialog

我的应用程序显示内部有AlertDialog的{​​{1}}。一切都工作得很好然后我决定测试这个内存泄漏。运行应用程序一段时间后,我打开了MAT并生成了泄漏嫌疑人报告。 MAT发现了几个类似的泄漏:

  

“< system class loader>”加载的“com.android.internal.app.AlertController $ RecycleListView”的一个实例占用......

我花了很多时间寻找这次泄漏的原因。代码审查没有帮助我,我开始谷歌搜索。这就是我发现的:

Issue 5054: AlertDialog seems to cause a memory leak through a Message in the MessageQueue

我决定检查这个bug是否重现。为此我创建了一个由两个活动组成的小程序。 ListView是一个恩赐点。它只包含一个运行MainActivity的按钮。后者只在其LeakedActivity方法中显示AlertDialog。这是代码:

onCreate()
每次public class MainActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); findViewById(R.id.button).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { startActivity( new Intent(MainActivity.this, LeakedActivity.class)); } }); } } public class LeakedActivity extends Activity { private static final int DIALOG_LEAK = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState == null) { showDialog(DIALOG_LEAK); } } @Override protected Dialog onCreateDialog(int id) { if (id == DIALOG_LEAK) { return new AlertDialog.Builder(this) .setTitle("Title") .setItems(new CharSequence[] { "1", "2" }, new OnClickListener() { private final byte[] junk = new byte[10*1024*1024]; @Override public void onClick(DialogInterface dialog, int which) { // nothing } }) .create(); } return super.onCreateDialog(id); } } 被解雇且com.android.internal.app.AlertController$RecycleListView完成时,

MAT报告此应用程序泄漏AlertDialog

我在这个小程序中找不到任何错误。它看起来像是使用LeakedActivity的一个非常简单的情况,它必须运作良好,但似乎没有。因此,我想知道在对项目使用AlertDialog时如何避免内存泄漏。为什么这个问题没有修复呢?提前谢谢。

4 个答案:

答案 0 :(得分:27)

(2012年12月12日):请参阅下面的更新。

此问题实际上并非由AlertDialog引起,而是与ListView更相关。您可以使用以下活动重现相同的问题:

public class LeakedListActivity extends ListActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Use an existing ListAdapter that will map an array
    // of strings to TextViews
    setListAdapter(new ArrayAdapter<String>(this,
            android.R.layout.simple_list_item_1, mStrings));
    getListView().setOnItemClickListener(new OnItemClickListener() {
        private final byte[] junk = new byte[10*1024*1024];
        @Override
        public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
                long arg3) {
        }
    });     
}
    private String[] mStrings = new String[] {"1", "2"};
}

多次旋转设备,您将获得OOM。

我没有调查更多关于什么是真正的原因的时候(我知道的什么的发生,但没有明确的为什么的,它的发生;可以是bug,或者设计)。但是你可以做一个解决方法,至少在你的情况下避免使用OOM。

首先,您需要保留对泄露的AlertDialog的引用。您可以在onCreateDialog()中执行此操作。当您使用setItems()时,AlertDialog会在内部创建ListView。当您在onClickListener()来电中设置setItems()时,会在内部将其分配给ListView onItemClickListener()

然后,在泄漏的活动的onDestroy(),将AlertDialog的{​​{1}}的{​​{1}}到ListView,它会释放出参考监听器使该监听器内分配的任何内存都符合GC的条件。这样你就不会得到OOM。这只是一个解决方法,真正的解决方案实际上应该包含在onItemClickListener()中。

以下是null的示例代码:

ListView

更新(2012年12月2日):经过进一步调查后,此问题实际上与onDestroy()@Override protected void onDestroy() { super.onDestroy(); if(leakedDialog != null) { ListView lv = leakedDialog.getListView(); if(lv != null) lv.setOnItemClickListener(null); } } 无关,而是与GC事实有关不会立即发生,需要时间来决定哪些对象符合条件并为GC做好准备。试试这个:

ListView

旋转几次,你就会得到OOM。问题是在你旋转之后,OnItemClickListener仍然保留,因为GC还没有,也不会发生(如果你使用MAT,你会看到这个public class MainActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // this will create reference from button to // the listener which in turn will create the "junk" findViewById(R.id.button).setOnClickListener(new View.OnClickListener() { private byte[] junk = new byte[10*1024*1024]; @Override public void onClick(View v) { // do nothing } }); } } 仍然被按钮保留听众从GCroot内心深处,这将需要时间GC来决定是否该junk可享有并且可以GCed)。但在同一时间,一个新的junk需要后创建旋转,并且由于mem alloc大小(每个垃圾10M),这将导致OOM。

的解决方案是打破任何引用到听者(在junk所有者),在这种情况下,从该按钮时,这实际上使得听者与仅短路径到垃圾一个GCroot并使GC决定更快地收回垃圾记忆。这可以在junk

中完成
junk

答案 1 :(得分:1)

无法重现Android 2.3.4 2.3.3。我在实际设备上测试了您的确切代码,并且从我在LogCat中看到的,堆大小随时间保持不变。可悲的是,我无法对我的转储进行混乱(错误:期待1.0.3)

08-19 08:41:58.026: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 13K, 50% free 2698K/5379K, external 83K/519K, paused 16ms
08-19 08:41:58.056: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1K, 43% free 3720K/6471K, external 83K/519K, paused 18ms
08-19 08:45:30.113: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1076K, 58% free 2723K/6471K, external 595K/1042K, paused 18ms
08-19 08:45:30.143: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 6K, 43% free 3740K/6471K, external 507K/1019K, paused 19ms
08-19 08:45:35.869: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1087K, 58% free 2726K/6471K, external 595K/1019K, paused 18ms
08-19 08:45:35.899: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 6K, 43% free 3744K/6471K, external 552K/1019K, paused 18ms
08-19 08:45:39.112: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1077K, 58% free 2734K/6471K, external 595K/1019K, paused 17ms
08-19 08:45:39.152: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 6K, 43% free 3752K/6471K, external 530K/1019K, paused 20ms
08-19 08:46:14.186: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1089K, 58% free 2736K/6471K, external 595K/1019K, paused 23ms
08-19 08:46:14.216: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 4K, 42% free 3755K/6471K, external 552K/1019K, paused 21ms
08-19 08:46:16.519: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1092K, 58% free 2736K/6471K, external 595K/1019K, paused 23ms
08-19 08:46:16.549: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 6K, 42% free 3753K/6471K, external 530K/1019K, paused 22ms
08-19 08:47:15.686: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1089K, 58% free 2736K/6471K, external 595K/1019K, paused 18ms
08-19 08:47:15.716: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 3K, 42% free 3756K/6471K, external 561K/1019K, paused 18ms
08-19 08:48:01.391: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1077K, 58% free 2736K/6471K, external 595K/1019K, paused 19ms
08-19 08:48:01.421: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 6K, 43% free 3753K/6471K, external 530K/1019K, paused 19ms
08-19 08:48:09.409: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1089K, 58% free 2737K/6471K, external 758K/1019K, paused 18ms
08-19 08:48:09.449: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 4K, 42% free 3756K/6471K, external 561K/1019K, paused 21ms
08-19 08:48:11.771: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1076K, 58% free 2736K/6471K, external 595K/1019K, paused 18ms
08-19 08:48:11.811: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 6K, 42% free 3754K/6471K, external 530K/1019K, paused 20ms
08-19 08:48:13.653: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1089K, 58% free 2737K/6471K, external 595K/1019K, paused 18ms
08-19 08:48:13.683: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 3K, 42% free 3758K/6471K, external 561K/1019K, paused 19ms
08-19 08:48:15.785: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1077K, 58% free 2736K/6471K, external 595K/1019K, paused 18ms
08-19 08:48:15.825: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 6K, 42% free 3754K/6471K, external 530K/1019K, paused 19ms
08-19 08:48:18.227: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1088K, 58% free 2737K/6471K, external 595K/1019K, paused 19ms
08-19 08:48:18.257: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 4K, 42% free 3756K/6471K, external 552K/1019K, paused 20ms
08-19 08:49:06.575: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1075K, 58% free 2736K/6471K, external 595K/1019K, paused 18ms
08-19 08:49:06.605: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 6K, 42% free 3754K/6471K, external 530K/1019K, paused 17ms
08-19 08:49:09.668: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1097K, 58% free 2729K/6471K, external 595K/1019K, paused 18ms
08-19 08:49:09.708: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 4K, 43% free 3748K/6471K, external 552K/1019K, paused 20ms
08-19 08:49:12.440: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1077K, 58% free 2736K/6471K, external 595K/1019K, paused 18ms
08-19 08:49:12.470: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 6K, 43% free 3753K/6471K, external 530K/1019K, paused 17ms
08-19 08:49:15.473: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1088K, 58% free 2736K/6471K, external 595K/1019K, paused 18ms
08-19 08:49:15.503: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 4K, 42% free 3756K/6471K, external 561K/1019K, paused 17ms
08-19 08:49:18.476: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1091K, 58% free 2737K/6471K, external 595K/1019K, paused 18ms
08-19 08:49:18.506: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 6K, 42% free 3754K/6471K, external 507K/1019K, paused 20ms
08-19 08:49:21.289: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1090K, 58% free 2737K/6471K, external 595K/1019K, paused 18ms
08-19 08:49:21.319: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 6K, 42% free 3754K/6471K, external 484K/996K, paused 20ms
08-19 08:51:43.307: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1071K, 58% free 2723K/6471K, external 595K/996K, paused 17ms
08-19 08:51:43.338: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed <1K, 43% free 3747K/6471K, external 595K/996K, paused 20ms
08-19 08:51:45.620: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1086K, 58% free 2729K/6471K, external 595K/974K, paused 18ms
08-19 08:51:45.660: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 7K, 43% free 3745K/6471K, external 462K/974K, paused 20ms
08-19 08:51:47.421: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1080K, 58% free 2738K/6471K, external 595K/974K, paused 17ms
08-19 08:51:47.452: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 6K, 42% free 3755K/6471K, external 484K/974K, paused 19ms
08-19 08:52:56.949: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 27K, 58% free 2733K/6471K, external 83K/595K, paused 18ms
08-19 08:52:56.979: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed <1K, 42% free 3757K/6471K, external 83K/595K, paused 17ms
08-19 08:53:01.233: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1072K, 58% free 2727K/6471K, external 595K/1107K, paused 18ms
08-19 08:53:01.274: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 2K, 43% free 3749K/6471K, external 578K/1090K, paused 20ms
08-19 08:53:04.046: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1081K, 58% free 2740K/6471K, external 595K/1064K, paused 18ms
08-19 08:53:04.086: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 6K, 42% free 3758K/6471K, external 530K/1042K, paused 20ms
08-19 08:53:25.948: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1090K, 58% free 2740K/6471K, external 595K/1042K, paused 19ms
08-19 08:53:25.978: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 6K, 42% free 3758K/6471K, external 552K/1042K, paused 19ms
08-19 08:57:51.246: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1099K, 58% free 2753K/6471K, external 595K/1042K, paused 18ms
08-19 08:57:51.286: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 13K, 42% free 3764K/6471K, external 561K/1042K, paused 20ms
08-19 09:00:47.699: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1106K, 58% free 2731K/6471K, external 595K/1019K, paused 18ms
08-19 09:00:47.729: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 7K, 43% free 3748K/6471K, external 484K/996K, paused 17ms
08-19 09:00:56.817: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1080K, 58% free 2741K/6471K, external 595K/996K, paused 18ms
08-19 09:00:56.848: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 6K, 42% free 3758K/6471K, external 530K/996K, paused 23ms
08-19 09:01:00.701: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1077K, 58% free 2739K/6471K, external 595K/996K, paused 19ms
08-19 09:01:00.731: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 6K, 42% free 3756K/6471K, external 530K/996K, paused 22ms
08-19 09:01:25.916: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 1077K, 58% free 2739K/6471K, external 595K/996K, paused 18ms
08-19 09:01:25.946: DEBUG/dalvikvm(3510): GC_FOR_MALLOC freed 6K, 42% free 3756K/6471K, external 530K/996K, paused 20ms

答案 2 :(得分:0)

我已经运行了你的代码,当我第一次按下按钮时,它显示LeakedActivity对话框和onClick它正在删除对话框,但活动仍然在黑色屏幕的前景。在按下后退键然后再次启动活动时,它显示内存没有错误异常:

ERROR/AndroidRuntime(263): java.lang.OutOfMemoryError

然后我从对话框代码中删除了行private final byte[] junk = new byte[10*1024*1024];,之后就不存在这样的问题....不知道为什么有人可以把这个东西放进文字中,多亏了他/她..

I tested the code in emulator android 2.1

答案 3 :(得分:-2)

您需要从onClick方法中解除/取消对话框,如下例所示:Alert Dialogs in Android