Android开发中常见内存泄漏问题
来源:互联网 发布:数据预处理的基本原理 编辑:程序博客网 时间:2024/05/21 12:09
一、内存泄漏原因
当一个对象不再使用时,本该被回收,而另一个正在使用的对象持有它的引用导致不能被回收,就产生了内存泄漏。
二、内存泄漏的影响
Android系统为每个应用程序分配的内存有限,当应用中内存泄漏较多时,轻则造成可用空间不足,频繁发生gc,表现为应用运行卡顿;重则导致内存溢出应用crash。
三、常见内存泄漏及解决办法
3.1 单例造成内存泄漏
public class AppManager{ private static volatile AppManager instance = null; private Context mContext; private AppManager(Context context){ this. mContext = context; } public static AppManager getInstance(Context context){ if(null == instance){ synchronized(AppManager.class){ if(null == instance){ instance = new AppManager(context); } } } return instance; }}
ps:单例模式为何加双重检查?申明单例的静态引用为何加volatile
关键字?
由于单例的生命周期和Application一样长,当Context所对应的Activity退出时,由于单例持有该Activity的引用,造成Activity退出时内存不能得到回收。
修正方法: this. mContext = context;
改为 this. mContext = context.getApplicationContext();
无论传入什么Context,最终都将使用Application的Context,防止了内存泄漏。
3.2 非静态内部类创建静态实例造成内存泄漏
public class OuterClassActivity extern Activity{ private static Inner mInner = null; @Override protected void onCreate (Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if(null == mInner){ mInner = new Inner();//创建静态实例 } } private class Inner{//非静态内部类 //TODO }}
由于非静态内部类会持有外部类的引用,当在内部类创建非静态内部类的静态实例后,导致该静态实例会持续持有外部类的应用,造成内存资源不能正常回收。
修正方法:将内部类设为静态内部类,静态内部类不会持有外部类实例的引用,当需要用到外部类的方法或属性时,使用外部类实例的弱引用。例如内部类可以这么写
private static class Inner{ private WeakReference<OuterClassActivity> mActivity; public Inner(OuterClassActivity activity){ mActivity = new WeakReference<OuterClassActivity>( activity); }}
3.3 Handler造成的内存泄漏
public class MainActivity extends AppCompatActivity { private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { //TODO } };}
由于mHandler是Handler的非静态匿名内部类的实例,它会持有外部类Activity的引用。消息队列是在一个Looper线程中不断轮询处理消息,如果当这个Activity退出时消息还未处理完毕,消息队列中的Message持有mHandler实例的引用,mHandler又持有Activity的引用,导致Activity退出时无法释放内存,引发内存泄漏。
修正方法:创建静态的Handler内部类,然后对Handler持有的activity对象使用弱引用,这样可以避免Activity内存泄漏,不过Looper线程的消息队列还是可能会有待处理的消息,所以在Activity 的onDestory方法中应该移除消息队列中的消息。
public class MainActivity extends AppCompatActivity { private Handler mHandler = new MyHandler (this); private static class MyHandler extern Handler{ private WeakReference<Context> softRefContext; public MyHandler(Context context) { softRefContext = new WeakReference<Context>(context); } @Override public void handleMessage(Message msg) { //TODO } }; @Override protected void onDestroy() { if (mHandler != null){ mHandler.removeCallbacksAndMessages(null); mHandler = null; } super.onDestroy(); }}
3.4 线程造成的内存泄漏
为避免阻塞主线程,在Activity中创建线程执行耗时操作是比较常见的,如
new Thread(new Runnable() { @Override public void run() { Log.i(TAG, "线程创建成功,正在执行线程程序"); SystemClock.sleep(30*1000); //TODO }}).start();
上面的Runnable是一个匿名内部类,因此它对当前Activity有一个隐式引用。如果Activity在销毁之前,任务还未完成,将导致Activity的内存资源无法回收,造成内存泄漏。
正确做法:使用静态内部类,
static class MyRunnable implements Runnable{ @Override public void run() { Log.i(TAG, "线程创建成功,正在执行线程程序"); SystemClock.sleep(30*1000); }}//--------------------------------------------------------------------------new Thread(new MyRunnable()).start();
在Activity销毁时应该取消相应的任务,避免在后台执行浪费资源。
3.5 资源未关闭造成的内存泄漏
对于使用了BraodcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap
等资源的使用,应该在Activity销毁时及时关闭或者注销,否则这些资源将不会被回收,造成内存泄漏。
总结
非静态内部类、匿名内部类会隐式持有外部类对象,需要注意其生命周期,建议使用静态内部类配合弱引用访问外部类,避免一不小心造成内存泄漏。
并不是所有内部类只能使用静态内部类,当该类的生命周期不可控时,我们需要采用静态内部类。
内部类存在的意义:接口只能解决部分多重继承问题,而内部类可以使多重继承更加完善,当需要继承抽象类或者具体类时,只能使用内部类才能实现多重继承。
内存泄漏主要分为以下几种类型:
1.静态变量(包括但不限于单例)引起的内存泄漏。注意静态变量持有对象的生命周期。
2.非静态内部类引起的内存泄漏。静态内部类,弱引用访问。
3.匿名内部类引起的内存泄漏。静态内部类,弱引用访问。
4.资源未关闭引起的内存泄漏。退出前关闭资源。
- Android开发中常见内存泄漏问题
- android开发中内存泄漏问题总结
- 5个Android开发中比较常见的内存泄漏问题及解决办法
- 5个Android开发中比较常见的内存泄漏问题及解决办法
- 5个Android开发中比较常见的内存泄漏问题及解决办法
- 5个Android开发中比较常见的内存泄漏问题及解决办法
- Android开发中比较常见的内存泄漏问题及解决办法
- 5个Android开发中比较常见的内存泄漏问题及解决办法
- 5个Android开发中比较常见的内存泄漏问题及解决办法
- 5个Android开发中比较常见的内存泄漏问题及解决办法
- 5个Android开发中比较常见的内存泄漏问题及解决办法
- 5个Android开发中比较常见的内存泄漏问题及解决办法
- Android开发中比较常见的内存泄漏问题及解决办法
- 5个Android开发中比较常见的内存泄漏问题及解决办法
- 5个Android开发中比较常见的内存泄漏问题及解决办法
- 5个Android开发中比较常见的内存泄漏问题及解决办法
- 5个Android开发中比较常见的内存泄漏问题及解决办法
- Android开发中比较常见的内存泄漏问题及解决办法
- 对mysql数据库中字段为空的处理
- C# XML转Json
- Quartz之schedule定时任务
- Android中LeakCanary检测内存泄漏
- spi bitbang实现原理分析
- Android开发中常见内存泄漏问题
- 是该年的第几天
- qt创建多线程的几种方法
- idea(8) 远程部署和远程调试
- opencvSharp
- CASE WHEN 及 SELECT CASE WHEN的用法
- appserv的安装和使用方法。
- ueditor图片无法左右对齐的解决
- 在网上看到一篇文章,挺不错的,与大家分享一下