Thread objects not garbage collected after being finished

强颜欢笑 提交于 2019-12-04 11:26:26

问题


I noticed that my application is leaking memory. This can be seen in DDMS, and I managed to get a OutOfMemoryError.

I found the source of the leak. One of the activities has a thread running in the background. This thread is stopped in onDestroy(). It finishes running, as it can be seen in DDMS.

Now, if thread is started, the leak occurs, Activity is not garbage collected after being destroyed, because it is referenced by the thread. If thread is not started at all, everything is ok.

Here's simple example demonstrating this:

public class MainActivity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }

    volatile boolean finished = false;
    byte[] memoryEater = new byte[4 * 1024 * 1024];

    Thread thread = new Thread(new Runnable() {

        @Override
        public void run() {
            while (!finished) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            Log.d(getClass().getName(), "Thread finished");
        }
    });

    @Override
    protected void onDestroy() {
        super.onDestroy();
        finished = true;
    }

    public void startActivity(View view) {
        startActivity(new Intent(this, MainActivity.class));
    }

    public void startThread(View view) {
        thread.start();
    }
}

Add one button for starting new activity and one for starting a thread. Start new activity. After going back, the memory will be cleaned only if thread has not been started.

What is the cause of this behaviour?


回答1:


I have just figured out this same problem.

Tomasz, you are on the right track. There is NO bug in DDMS and there is NO memory leak in your program.

The really problem is you are running your program in DEBUG mode (under Eclipse). Somehow when Android is running in DEBUG mode, Threads are not garbage collected even after the run() method has been exited. I guess it is probably Android needs to hold on to the Thread for some debugging features to work.

But if you run you application in RUN mode (still under Eclipse), Thread garbage collection takes place. The Thread will be freed completely and your Activity will be freed completely.




回答2:


I kept investigating and what I've found is really suprising. It seems there is no real memory leak. It happens only when app is in debugging mode in DDMS.

DDMS seems to somehow hold references to those finished treads, preventing them from being GC-ed. When i disconnect the phone and connect again, I can see that all "leaked" resources have been released.

It looks like a bug in DDMS.




回答3:


The anonymous runnable class used by the thread would have a reference to the activity ('this'). As the thread is referenced by the activity, and the runnable in the thread references the activity, the GC will never collect either of them.

Try doing something more like this:

private static RunnableClass implements Runnable
{
    @Override
    public void run() {
        while (!finished) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        Log.d(getClass().getName(), "Thread finished");
    }
});

Thread thread = new Thread(new RunnableClass());



回答4:


Activities are not destroyed when "back" is pressed or any other intent is sent to remove it from the top of the stack. I don't think your overriden onDestroy() method is ever called until your Android OS runs out of memory. From the documentation one can extract:

As discussed in the following section about the activity lifecycle, the Android system manages the life of an activity for you, so you do not need to finish your own activities. Calling these methods could adversely affect the expected user experience and should only be used when you absolutely do not want the user to return to this instance of the activity.

Normally, every Activity instance is laying around in memory after initial creation and goes through onStart()...onStop() cycle without being destroyed. Implement onStop() and call finish() in it for MainActivity with the Thread to be released and consequently garbage collected.

UPDATE: The statement above is not true. Based on the code provided in the question, there is no reason the Activity should not be GC-ed.



来源:https://stackoverflow.com/questions/11640390/thread-objects-not-garbage-collected-after-being-finished

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!