使用定时器时出现内存泄漏问题

4

我正在使用一个计时器,在监听器事件上被取消并重新启动。除了定时器线程泄漏整个外部类之外,一切都运行良好。

我的计时器实现如下:

        if(timer != null) {
            timer.cancel();
            timer = null;
            timer = new Timer();
        }
        timer.schedule(new TimerTask() { // Thread leaks!!!!
            @Override
            public void run() {
              mCallback.onHeaderMoving(newToolbarTranslationY );
            }
        } , 150);

我使用MAT Analyser追踪问题,最终找到了这里。我还注释掉了回调行的代码,但是线程仍然泄漏,因此肯定是定时器本身出了问题。然而,我并不真正理解那段代码的问题所在。
根据我的研究,问题似乎是匿名内部类(new Timertask())持有对外部类的引用,因此可能会泄漏整个上下文。但我仍然不明白为什么定时器以及上下文引用在线程运行完毕之后(150毫秒+后)仍未被垃圾回收。
最后,我该如何解决这个泄漏问题?我将定时器设置为null,但这并没有解决我的问题。 编辑:
 private OnHeaderMovingCallBack mCallback;
 private Timer timer = new Timer();

 //... some other parameters


public ScrollingToolbarManager(View toolbar , View pagerStrip , AbsListView listView , OnHeaderMovingCallBack headerMovingCallBack){
    this.toolbar = toolbar;
    this.pagerStrip = pagerStrip;

    this.listView = listView;

    mCallback = headerMovingCallBack;

    changeStartValues();

}

public static interface OnHeaderMovingCallBack{
    public void onHeaderMoving(int translationY);
}

 public void moveHeader(){

      //... some calculations

    //timer implementation from above
 }

在ListView的滚动事件中调用moveHeader()函数。

timer 是如何定义的,它定义在哪里? - m0skit0
在类的头文件中只需声明“Timer timer;”?这是你的意思吗? - marcel12345689
我所说的头部只是指在类的开头 :) - marcel12345689
好的,我在包含列表视图的片段中执行此操作。它创建该类的对象并将列表视图传递给该类。但是由于对具有对位图引用的适配器引用的列表视图的引用,我正在泄漏位图。我认为我没有泄漏活动本身。 - marcel12345689
那么,内存泄漏的真正原因是什么?最终是什么解决方案帮助了你? - Prizoff
显示剩余2条评论
2个回答

3

如果您认为问题在于匿名内部类持有对外部类的引用,那么只需要使用静态命名内部类 - 这将不会持有任何引用。在您的类中放置像这样的内容:

static class MyTimerTask extends TimerTask {
    private OnHeaderMovingCallBack mCallback;
    int newToolbarTranslationY;

    public MyTimerTask(OnHeaderMovingCallBack mCallback, int newToolbarTranslationY) {
        this.mCallback = mCallback;
        this.newToolbarTranslationY = newToolbarTranslationY;
    }

    @Override
    public void run() {
        mCallback.onHeaderMoving(newToolbarTranslationY);
    }
}

2

我和你有同样的问题。我发现当我将Timer定义为全局变量并且在活动结束时不将其设置为null时,它总是导致内存泄漏。 而当我将Timer定义为局部变量或将其设置为null时,问题就解决了。但我不明白为什么会这样。如果你已经解决了这个问题,请告诉我你的解决方案,谢谢!

public class TestActivity extends AppCompatActivity {
    private Timer mTimer;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);
        mTimer = new Timer();
        mTimer.schedule(new TimerTask() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, 0);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mTimer = null;
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接