java - Android Activity 从未被 GC 导致内存不足异常

标签 java android memory garbage-collection

我有两个Activity,都有一个内部类SurfaceView,它有一个内部类Thread。第一个是菜单屏幕,第二个是玩游戏的比赛屏幕。

要从第一个 Activity 开始第二个 Activity ,我这样做:

Intent intent = new Intent();
intent.setClass(Menu.this, RaceActivity.class);
intent.putExtra("level", level.getNumber());
startActivityForResult(intent, 0);

关卡完成后,从我运行的第二个 Activity 开始。

finish();

这会调用我的 onDestroy 方法。我的印象是这足以让我的第二个 Activity elligble 垃圾收集。但是当我完成比赛并多次开始新的比赛时,我发现我最终会撞车。在 Eclipse 中使用内存分析器工具 (MAT),我发现很多对我的第二个 Activity 的引用,并且 SurfaceView 和 Thread 仍然被保留。所以我也决定在 destroy 方法中清理它们。

public void onDestroy() {
    super.onDestroy();
    mPanel.mThread.destroy(); //destroys surfaceholder in thread
    mPanel.mThread = null;
    mPanel = null;
}

这似乎已经消除了几乎所有的东西。但是当我进入 MAT 时,我仍然看到一个对第二个 Activity 的引用(当选择路径到 GC 根时 -> 排除弱引用)

Class Name                                  | Shallow Heap | Retained Heap
---------------------------------------------------------------------------
com.moz.by.RaceActivity @ 0x405b6108 Unknown|          280 |         8,008
---------------------------------------------------------------------------

这是我正在尝试进行 GC 的 Activity 的名称,因此它似乎在某处持有对其自身的引用。那个或 Unknown 关键字在这里具有一定的意义。

我对这个问题感到困惑,因为我不确定下一步该去哪里寻找这个问题。我想知道我是否能找到这个 Activity 最终清理的问题!现在已经坚持了几天,所以我想我会向你们好人彻底解释我的问题。有人可能会提出我可能犯的初学者错误。

感谢阅读。

附言这是我的第一个应用程序,如果我在我的工作流程中遗漏了一些基本的东西,我深表歉意。下面是我开始和结束几场比赛后来自 MAT 的 dominator_tree 的一部分。

Class Name                                                            | Shallow Heap | Retained Heap | Percentage
------------------------------------------------------------------------------------------------------------------
com.moz.by.RaceActivity @ 0x405989e8 Unknown                          |          280 |         4,464 |      0.15%
com.moz.by.RaceActivity @ 0x405b6108 Unknown                          |          280 |         8,008 |      0.26%
com.moz.by.RaceActivity @ 0x406532e8 Unknown                          |          280 |         4,024 |      0.13%
com.moz.by.RaceActivity @ 0x4077f290 Unknown                          |          280 |         5,440 |      0.18%
com.moz.by.RaceActivity$Panel @ 0x40513d40 Unknown                    |          432 |         1,496 |      0.05%
com.moz.by.RaceActivity$Panel @ 0x40527148 Unknown                    |          432 |         1,496 |      0.05%
com.moz.by.RaceActivity$Panel @ 0x40653878 Unknown                    |          432 |         1,496 |      0.05%
com.moz.by.RaceActivity$Panel @ 0x40788490 Unknown                    |          432 |         1,496 |      0.05%
com.moz.by.RaceActivity$TutorialThread @ 0x40569580  Thread-35        |          120 |           192 |      0.01%
com.moz.by.RaceActivity$TutorialThread @ 0x40642558  Thread-37 Unknown|          120 |           192 |      0.01%
com.moz.by.RaceActivity$TutorialThread @ 0x40683108  Thread-59 Unknown|          120 |           120 |      0.00%
com.moz.by.RaceActivity$TutorialThread @ 0x406a56f0  Thread-57        |          120 |           192 |      0.01%
com.moz.by.RaceActivity$TutorialThread @ 0x40706f20  Thread-51        |          120 |           192 |      0.01%
com.moz.by.RaceActivity$TutorialThread @ 0x40707fe8  Thread-45 Unknown|          120 |           192 |      0.01%
com.moz.by.RaceActivity$TutorialThread @ 0x4077fa10  Thread-53 Unknown|          120 |           192 |      0.01%
com.moz.by.RaceActivity$TutorialThread @ 0x40789da0  Thread-43        |          120 |           192 |      0.01%
------------------------------------------------------------------------------------------------------------------

编辑:

所以看起来对 RaceActivity 的最后引用是在内部类 TutorialThread 中,它似乎在 this$0 变量中持有对该类的引用。见下文。

Type   |Name          |Value
-----------------------------------------------------------
ref    |this$0        |com.moz.by.RaceActivity @ 0x4053b080
ref    |mSurfaceHolder|null
ref    |mPanel        |null
boolean|mRun          |false
-----------------------------------------------------------

我不确定为什么会这样,这就是我结束话题的方式。

boolean retry = true;
mThread.setRunning(false);
while (retry) {
  try {
    mThread.join();
    retry = false;
  } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
  }
}

我认为这应该结束线程,但由于奇怪的 this$0 变量中的最终引用,它永远不会被 GC 处理。任何人都知道这个变量是什么以及我如何清除它?

最佳答案

您喜欢这个 Activity ,可能是因为您对它有一些静态引用,或者您知道如何将它传递给下一个 Activity 。

顺便问一下,当你停止线程时,你是这样做的吗?

Thread myThread = new Thread();

        try {
            myThread.join();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        myThread = null;

你应该。

关于java - Android Activity 从未被 GC 导致内存不足异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8918922/

相关文章:

android - 检查android中的小屏幕支持

android - FirebaseListAdapter 空 View

java - 如何在Range Seekbar中设置进度间隔

c++ - 什么时候允许对 c++11 中的类型进行 memcpyed?

java - 变量在此位置只能为空结果集

java - 查找第三方库抛出的异常

java - POI无法打开工作簿打开.xls文件并且eclipse抛出异常

java - spring boot Controller 测试,mockMov 不模拟

c++11 - C++ std::atomic 和共享内存?

c - C中的GetTotalMemory分配