主页(http://www.kuwanit.com):android内存优化
内存泄漏
内存泄漏:是指程序在申请内存后,无法释放已申请的内存空间。内存泄漏简单地说就是申请了一块内存空间,使用完毕后没有释放掉。它的一般表现方式是程序运行时间越长,占用内存越多,最终用尽全部内存,整个系统崩溃。由程序申请的一块内存,且没有任何一个指针指向它,那么这块内存就泄露了。内存泄漏一般不会导致程序异常,但它会导致程序的内存占用过大,这将提高内存溢出的几率。所以,内存泄露是内存溢出的一种诱因,不是唯一因素。
内存泄漏是造成应用程序OOM的主要原因之一
静态变量:静态变量是在类被load的时候分配内存的,并且存在于方法区。当类被卸载的时候,静态变量被销毁。只要静态变量没有被销毁也没有置null,其对象一直被保持引用,也即引用计数不可能是0,因此不会被垃圾回收。
导致内存泄漏的代码如下:
上述代码Activity无法正常销毁,因为静态变量mContext引用了它。
2、单列模式导致的内存泄漏当单列中传入一个Activity的Context后,该单列就持有Activity的引用,我们知道单例的生命周期和Application的一样长,所以当Activity退出时它的内存并不会被回收。
所以,单例中的Context最好使用Application的Context,这样可以有效防止内存泄漏,如下:
这样的话,无论传入生命类型的Context,最终单例使用的都是Application的Context
3、属性动画导致的内存泄漏属性动画中有一类无限循环的动画,如果在Activity中播放此动画且没有在onDestory中停止动画,即使已经无法在界面上看到动画效果,动画也会一直播放下去,并且这个时候Activity的View会被动画持有,而View有持有了Activity,最终导致Activity无法释放。这种泄漏的解决办法是在onDestory中调用animator.cancal()来停止动画。
4、Handler造成的内存泄漏大家平时开发中喜欢在Activity中直接new一个Handler的匿名内部类,在Java中,非静态的内部类或者匿名类会隐式的持有其外部类的引用,而静态的内部类则不会。这样造成匿名内部类持有一个外部类(通常是Activity)的引用(不然怎么更新ui),但是Handler常常伴随着一个执行耗时操作的异步线程(如下载多张图片),如果在完成耗时操作之前,Activity退出,异步线程持有handler的引用,handler持有Activity的引用,从而导致内存泄漏。如下:
public class MainActivity extends AppCompatActivity { private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { // do something } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); loadData(); } private void loadData(){ //...do request Message message = Message.obtain(); mHandler.sendMessage(message); } }我们可以通过下面的方法来规避上述问题:
public class MainActivity extends AppCompatActivity { /** * 创建一个静态Handler内部类,然后对Handler持有的对象使用弱引用,这样在回收时也可以回收Handler持有的对象, * 这样虽然避免了Activity泄漏,不过Looper线程的消息队列中还是可能会有待处理的消息, * 所以我们在Activity的Destroy时或者Stop时应该移除消息队列中的消息, */ private MyHandler mHandler = new MyHandler(this); private TextView mTextView ; private static class MyHandler extends Handler { private WeakReference<Context> reference; public MyHandler(Context context) { reference = new WeakReference<>(context); } @Override public void handleMessage(Message msg) { MainActivity activity = (MainActivity) reference.get(); if(activity != null){ activity.mTextView.setText(""); } } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTextView = (TextView)findViewById(R.id.textview); loadData(); } private void loadData() { //...request Message message = Message.obtain(); mHandler.sendMessage(message); } @Override protected void onDestroy() { super.onDestroy(); // 移除消息队列中所有消息和所有的Runnable, mHandler.removeCallbacksAndMessages(null); // 当然,也可以使用mHandler.removeCallbacks();或mHandler.removeMessages();来移除指定的Runnable和Message。 } } 5、上下文对象导致的内存泄漏 6、线程造成的内存泄漏 public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); /** * 错误的做法 * 异步任务和Runnable都是一个匿名内部类,因此它们对当前Activity都有一个隐式引用。 * 如果Activity在销毁之前,任务还未完成,那么将导致Activity的内存资源无法回收,造成内存泄漏 */ new AsyncTask<Void, Void, Void>() { @Override protected Void doInBackground(Void... params) { SystemClock.sleep(10000); return null; } }.execute(); new Thread(new Runnable() { @Override public void run() { SystemClock.sleep(10000); } }).start(); /** * 正确的做法:使用静态内部类 * 避免了Activity的内存资源泄漏,当然在Activity销毁时候也应该取消相应的任务AsyncTask::cancel(),避免任务在后台执行浪费资源 */ new Thread(new MyRunnable()).start(); new MyAsyncTask(this).execute(); } static class MyAsyncTask extends AsyncTask<Void, Void, Void> { private WeakReference<Context> weakReference; public MyAsyncTask(Context context) { weakReference = new WeakReference<>(context); } @Override protected Void doInBackground(Void... params) { SystemClock.sleep(10000); return null; } @Override protected void onPostExecute(Void aVoid) { super.onPostExecute(aVoid); MainActivity activity = (MainActivity) weakReference.get(); if (activity != null) { //... } } } static class MyRunnable implements Runnable{ @Override public void run() { SystemClock.sleep(10000); } } }更多线程内容请查看Android中的线程池 ThreadPoolExecutor
7、webview导致的内存泄漏优化请参考:
发表评论愿您的每句评论,都能给大家的生活添色彩,带来共鸣,带来思索,带来快乐。