【问题标题】:How do I fix this Android memory leak involving Threads?如何修复这个涉及线程的 Android 内存泄漏?
【发布时间】:2013-10-04 03:43:50
【问题描述】:

所以我发现,随着MAT,我不断创建多个Threads,每个surfaceCreate

我认为我需要这些线程,但是当用户浏览我的应用程序时,这种方法会导致多个 ViewThread 实例,这是内存泄漏。

如何重新组织创建和处理线程的方式,以免发生这种情况,或者如何阻止泄漏的发生?

@Override
public void surfaceCreated(SurfaceHolder holder) {
    loading=false;
    if (!mThread.isAlive()){
        mThread = new ViewThread(this);
        mThread.setMenuRunning(true);
        mThread.start();
    }
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {

    if (mThread.isAlive()){ 
        mThread.setMenuRunning(false);
    }
}

我五次打开并离开游戏的 Career Activity,这就是 MAT 上显示的内容

编辑:我发现依赖surfaceDestroyed 来销毁我的线程是不可靠的。我现在从不同的方法调用适当的线程破坏调用,触发onPause

【问题讨论】:

    标签: android memory-leaks


    【解决方案1】:

    您应该使用 Wea​​kReference 来引用您线程中的职业。这样,当没有更多对职业的硬引用时,引用将被清除。

    您可以通过右键单击职业并选择 Path To GC Roots 来跟踪 MAT 中的所有引用,然后选择所有引用。这将向您显示内存中保留的对象的路径。确保在完成活动后清除这些引用,或者使用 Wea​​kReferences 让 GC 自动清除它们。

    【讨论】:

    • 我试过了,我班的那些多个实例还在堆积。
    • 在这种情况下,您可以使用 MAT 查找从 gc 根到对象的路径。您可能会在侦听器/观察者或其他地方的某个地方找到另一个参考。这也可能是一个匿名内部类。在这种情况下尝试使用对类实例的弱引用的静态类。这将在 gc 运行后立即断开链接。您也可以尝试在适当的时候手动取消注册监听器。如果这不起作用,您可以分享一个 MAT 的屏幕截图,显示 GC 根的路径吗?
    【解决方案2】:

    surfaceDestroyed 中,您应该等待以确保线程在您返回之前停止。

    您可以参考this question了解更多详情

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        boolean retry = true;
        mThread.setRunning(false);
        while (retry) {
            try {
                mThread.join();
                retry = false;
            } catch (InterruptedException e) {
            }
        }
    }
    

    【讨论】:

    • 我试过这个,但似乎没有用。查看转储时,我仍然看到了多个线程实例。
    【解决方案3】:

    所以我通过注释一行来修复它:

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        loading=false;
        if (!mThread.isAlive()){
            //mThread = new ViewThread(this);
            mThread.setMenuRunning(true);
            mThread.start();
        }
    }
    

    这也与WeakReferenceSurfaceDestroyed 答案结合使用。 我稍后会测试它并确定它是否只是删除了那一行,或者它与弱引用的组合,或者其他东西,然后奖励答案

    【讨论】:

    • 那是正确的。重要的是要注意原始思想中的缺陷。 isAlive() 需要有效的对象引用,因此不能很好地指示您是否需要新的 Thread 对象。如果您有一个无效的有效线程,isAlive() 将返回 false ...因此创建一个新线程 is !isAlive() 会导致您描述的行为。决定是否应添加新线程的唯一有效方法是检查空指针引用。无论如何检查空指针是个好习惯:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-05-09
    • 2017-02-04
    • 2010-11-30
    • 2022-01-01
    • 1970-01-01
    • 2011-10-09
    • 1970-01-01
    相关资源
    最近更新 更多