线程也是造成内存泄露的一个重要的源头。线程产生内存泄露的主要原因在于线程生命周期的不可控。
1.看一下下面是否存在问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); exampleOne(); } private void exampleOne() { new Thread() { @Override public void run() { while (true) { SystemClock.sleep(1000); } } }.start(); } }
这段代码很平常也很简单,是我们经常使用的形式。
真的没有问题吗 我们思考一个问题:假设Thread的run函数是一个很费时的操作,当我们开启该线程后,将设备的横屏变为了竖屏,一般情况下当屏幕转换时会重新创建Activity,按照我们的想法,老的Activity应该会被销毁才对,然而事实上并非如此。由于我们的线程是Activity的内部类,所以Thread中保存了Activity的一个引用,当Thread的run函数没有结束时,Thread是不会被销毁的,因此它所引用的老的Activity也不会被销毁,因此就出现了内存泄露的问题。
2.这种线程导致的内存泄露问题应该如何解决呢?
将线程的内部类,改为静态内部类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); exampleTwo(); } private void exampleTwo() { new MyThread().start(); } private static class MyThread extends Thread { @Override public void run() { while (true) { SystemClock.sleep(1000); } } } }
使用静态内部类,切断了Thread对于Activity的引用。
注意上述方法虽然解决了Activity的内存泄露,但是依然存在问题,那就是Activity被销毁后,Thread依然在运行中,占用着资源,对此可以这样解决:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 public class MainActivity extends Activity { private MyThread mThread; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); exampleThree(); } private void exampleThree() { mThread = new MyThread(); mThread.start(); } /** * Static inner classes don't hold implicit references to their * enclosing class, so the Activity instance won't be leaked across * configuration changes. */ private static class MyThread extends Thread { private boolean mRunning = false; @Override public void run() { mRunning = true; while (mRunning) { SystemClock.sleep(1000); } } public void close() { mRunning = false; } } @Override protected void onDestroy() { super.onDestroy(); mThread.close(); } }
关于Thread的内存泄露,还存在以下的情况,解决办法:
第一、将线程的内部类,改为静态内部类。 第二、在线程内部采用弱引用保存Context引用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class ThreadActivity extends Activity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); new MyThread().start(); } private class MyThread extends Thread { @Override public void run() { super.run(); dosomthing(); } } private void dosomthing(){ while(true){ } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 public class ThreadActivity extends AppCompatActivity { private boolean isRuning = true; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_thread); new MyThread(this).start(); } private void dosomthing() { while(isRuning){ System.out.println("yunxing...."); } } private void stop(){ isRuning=false; } private static class MyThread extends Thread { WeakReference<ThreadActivity> mThreadActivityRef; public MyThread(ThreadActivity activity) { mThreadActivityRef = new WeakReference<>( activity); } @Override public void run() { super.run(); if (mThreadActivityRef == null) return; if (mThreadActivityRef.get() != null) mThreadActivityRef.get().dosomthing(); } } @Override protected void onDestroy() { super.onDestroy(); stop(); } }
参考链接:Activitys, Threads, & Memory Leaks Android App 内存泄露之Thread
上一篇:AsyncTask内存泄露
下一篇:绘制优化,响应速度优化,线程优化