什么是内存泄漏?
内存泄漏是当程序不再使用到的内存时,释放内存失败而产生了无用的内存消耗。内存泄漏并不是指物理上的内存消失,这里的内存泄漏是值由程序分配的内存但是由于程序逻辑错误而导致程序失去了对该内存的控制,使得内存浪费。
怎样会导致内存泄漏?
资源对象没关闭造成的内存泄漏,如查询数据库后没有关闭游标cursor
构造Adapter时,没有使用 convertView 重用
Bitmap对象不在使用时调用recycle()释放内存
对象被生命周期长的对象引用,如activity被静态集合引用导致activity不能释放
以下写的代码都是正确解决内存泄漏的代码
内存泄漏有什么危害?
内存泄漏对于app没有直接的危害,即使app有发生内存泄漏的情况,也不一定会引起app崩溃,但是会增加app内存的占用。内存得不到释放,慢慢的会造成app内存溢出。所以我们解决内存泄漏的目的就是防止app发生内存溢出
1、新建线程引起的Activity内存泄漏
public class TestRunActivity extends Activity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activitiy_main); new Thread(new MyRunnable()).start(); findViewById( R.id.pic).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { finish(); } }); } private static class MyRunnable implements Runnable { @Override public void run() { try { Thread.sleep( 15000 ); } catch (InterruptedException e) { e.printStackTrace(); } } } }
这个必须MyRunnable是静态内部类,如果不是,点击finish按钮的时候因为非静态内部类会持有activity的引用,会导致activity的内存得不到释放
2、Activity添加监听器造成Activity内存泄漏
public class TestRunActivity extends Activity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activitiy_main); NastyManager.getInstance().addListener(this); }
这个是在开发中经常会犯的错误,NastyManager.getInstance() 是一个单例,当我们通过 addListener(this) 将 Activity 作为 Listener 和 NastyManager 绑定起来的时候,不好的事情就发生了。
如何改进?
想要修复这样的 Bug,其实相当简单,就是在你的 Acitivity 被销毁的时候,将他和 NastyManager 取消掉绑定就好了。
3、Handler 匿名内部类造成内存溢出?
public class HandlerActivity extends AppCompatActivity { private final static int MESSAGECODE = 1 ; private static Handler handler ; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activitiy_main); findViewById( R.id.pic ).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { finish(); } }); //创建Handler handler = new MyHandler( this ) ; //创建线程并且启动线程 new Thread( new MyRunnable() ).start(); } private static class MyHandler extends Handler { WeakReference<HandlerActivity> weakReference ; public MyHandler(HandlerActivity activity ){ weakReference = new WeakReference<HandlerActivity>( activity) ; } @Override public void handleMessage(Message msg) { super.handleMessage(msg); if ( weakReference.get() != null ){ // update android ui Log.d("mmmmmmmm" , "handler " + msg.what ) ; } } } private static class MyRunnable implements Runnable { @Override public void run() { handler.sendEmptyMessage( MESSAGECODE ) ; try { Thread.sleep( 8000 ); } catch (InterruptedException e) { e.printStackTrace(); } handler.sendEmptyMessage( MESSAGECODE ) ; } } @Override protected void onDestroy() { super.onDestroy(); //如果参数为null的话,会将所有的Callbacks和Messages全部清除掉。 handler.removeCallbacksAndMessages( null ); } }
我们看上面的正确代码,要把MyHandler声明为静态内部类,然后传入的activity为 WeakReference ,也就是所谓的弱引用。垃圾回收器在回收的时候,是会忽视掉弱引用的,所以包含它的 Activity 会被正常清理掉这样就不会发生内存泄漏。在onDestroy() 里面也要移除所有的callback 和 Message 。
4、AsyncTask造成内存泄漏
public class TestRunActivity extends AppCompatActivity { private MyTask myTask; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activitiy_main); findViewById( R.id.pic ).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { finish(); } }); myTask = new MyTask(); myTask.execute(); } @Override protected void onDestroy() { super.onDestroy(); if(myTask != null) { myTask.cancel(true); } } class static MyTask extends AsyncTask<Void,Void,Void> { @Override protected Void doInBackground(Void... voids) { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } return null; } } }
自定义静态AsyncTask类
AsyncTask的周期和Activity周期保持一致。也就是在Activity生命周期结束时要将AsyncTask cancel掉。