How do I fix this Android memory leak involving Th

2019-06-16 17:05发布

问题:

So I've found, with the MAT that I keep creating multiple Threads with every surfaceCreate

I think I need these threads, though, but this method causes multiple instances of ViewThread, as a user navigates through my app, which is a memory leak.

How can I reorganize the way my threads are created and handled so that this doesn't happen, or how can I stop the leak from occurring?

@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);
    }
}

I opened and navigated away from the Career Activity of my game five times, and this is what shows up on the MAT

EDIT: I've since found that depending on surfaceDestroyed for the destruction of my threads is unreliable. I now call the appropriate thread-destroying calls from a different method, triggered onPause.

回答1:

You should use a WeakReference to reference the Career in your Thread. This way the reference will be cleared when there are no more hard references to the Career.

You can track all references in MAT by right clicking the career and choosing Path To GC Roots, then with all references. This will show you the path(s) to the object retained in memory. Make sure you either clear those references when you are done with the activity or make use of WeakReferences to have the GC clear them automatically.



回答2:

Inside surfaceDestroyed, you should wait to make sure that the thread stopped before you return.

You can refer to this question, for more details

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


回答3:

So I fixed it by commenting one line:

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

This was also combined with the WeakReference and the SurfaceDestroyed answers. I'll test it later and determine if it's just the removal of that one line, or a combination of that and the weak reference, or the other thing, then award the answer