实例中的内存泄漏

Mar*_*tek 7 java memory performance android memory-leaks

我一直在努力识别内存泄漏.我想我的项目循环进度视图中有几个内存泄漏.

我的一个猜测是内部类中有内存泄漏FadeRunnable.但说实话,我不确切知道如何确定这是否是问题的根源.好吧,当我按常规方案切换方向时,我看到内存使用量增加,如下所示.如果我注释掉FadeRunnable该类的用法,步骤会更小(但仍然存在,所以我猜这不是唯一的泄漏)

记忆步骤

一旦我分析堆转储,我看到了一些东西.但实际上我不知道这些值是什么意思.我做的事情是

  1. 多次改变方向
  2. 打开堆转储并按'保留大小'排序
  3. 现在,当我点击"CircularProgressView"时,我在右侧区域看到了8行.我猜这意味着有8个'CircularProgressView'实例泄露并在内存中作为孤儿存在.

它是否正确?如果是这样,我如何找到保存/保存此对象的转储信息(我猜在下部窗格中的某个位置).

堆转储

我希望能够逐步解释如何找出是否以及哪个对象泄漏了一些内存.

可以在本课程中找到所有可疑视图的代码.

https://github.com/momentummodules/CircularProgressView/blob/master/circularprogressview/src/main/java/momentum/circularprogressview/CircularProgressView.java

但是也可以随时查看整个项目以获得更深入的洞察力,以及是否想要玩它.

提前致谢!

UPDATE

上面的代码链接显示了内存泄漏内部类的固定代码.以下代码段显示了永远不应该使用的原始内存泄漏代码

/**
 * Mem-leaking code, for fixed code see repository link
 * https://github.com/momentummodules/CircularProgressView/blob/master/circularprogressview/src/main/java/momentum/circularprogressview/CircularProgressView.java
 */
public class CircularProgressView extends View
{
    ...
    private Thread fadeThread = null;
    ...

    ...
    class FadeRunnable implements Runnable
    {
        @Override
        public void run()
        {
            ...
        }
    }
    ...

    ...   
    private void startFade(boolean fadeIn)
    {
        // check existing
        if(this.fadeThread != null)
        {
            // check if fade is already running
            switch(this.fadeThread.getState())
            {
                case TERMINATED:
                case NEW:
                    this.fadeThread = null;
                    break;
                case RUNNABLE:
                case BLOCKED:
                case TIMED_WAITING:
                case WAITING:
                    return;
            }
        }
        // create new
        this.fadeThread = new Thread(new FadeRunnable(fadeIn, this.fadeTime));
        this.fadeThread.start();
    }
}
Run Code Online (Sandbox Code Playgroud)

mac*_*usz 5

是的,你在FadeRunnable课堂上确实有内存泄漏.

内部类的每个实例都包含对其外部类的隐式引用,可通过OuterClass.this运算符访问.在你的项目中,当你FadeRunnable通过方向改变执行然后触发重新配置时,整个活动和你所CircularProgressView包含的内容被重新创建,但是FadeRunnablefrom之前仍然存活(已分配),并且由于它持有对其外部CircularProgressView类的隐式引用,视图继续存在,这就是为什么在几次重新配置之后你CircularProgressView在内存中分配了8个实例,并且情况变得更糟 - 每个View都保持对它的上下文的引用,而且这也不能被释放,导致内存泄漏.

Runnables,Handlers和类似的对象可以超出它们的封闭活动,片段,视图等,应该声明为标准类或STATIC内部类(静态内部类不包含对其外部类的隐式引用),并且应该'瞒着如引用Context,View等等,而不是你能保持WeakReference<>这样,当你Activity通过配置变化重建中,View可以被摧毁,并通过垃圾收集器释放.

这是一篇关于这个主题的非常翔实的文章,我强烈建议阅读它.