Android内存泄露分析以及处理

基础知识:
java的内存分配


静态存储区:编译时就分配好,在程序整个运行期间都存在。它主要存放静态数据和常量;


栈区:当方法执行时,会在栈区内存中创建方法体内部的局部变量,方法结束后自动释放内存;


堆区:通常用来存放new出来的对象。由java垃圾回收期回收。


四种引用类型的介绍:


强引用(StrongReference):JVM 宁可抛出 OOM ,也不会让 GC 回收具有强引用的对象;


软引用(SoftReference):只有在内存空间不足时,才会被回的对象;


弱引用(WeakReference):在 GC 时,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,
都会回收它的内存;


虚引用(PhantomReference):任何时候都可以被GC回收,当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,
就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。程序可以通过判断引用队列中是否存在该对象的虚引用,来了解这个对象是否将要被回收。可以用来作为GC回收Object的标志。


内存泄露检测工具
1. MAT(Memory Analyzer Tool),下载地址:


http://www.eclipse.org/mat/downloads.php


2. 强大的开源内存检测工具 LeakCanary。


leakcanary 是一个开源项目,一个内存泄露自动检测工具,是著名的 GitHub开源组织Square贡献的,它的主要优势就在于自动化过早的发觉内存泄露、配置简单、抓取贴心,缺点在于还存在一些bug,不过正常使用百分之九十情况是OK的,其核心原理与MAT工具类似。


因为配置十分简单,只需要几句话就好!!!这里就不多说了,大家可以看官方文档:


https://github.com/square/leakcanary
1.在使用单例模式时,如果我们传入的Context是Activity的Conetxt,当这个对应的Activity退出时,
由于该Context的引用被单例对象所持有,其生命周期等于整个应用的生命周期,所以当前Activity退
出时它的内存并不会回收,所以会造成内存泄露
code:
	public class SingleDemo{
		private static SingleDemo mSingleDemo;
		private Context mConetxt;
		
		private SingleDemo(Context context){
			//获取Application的Context避免有泄露
			this.mContext=context.getApplicationContext();
		}
		
		private static SingleDemo getInstance(Context context){
			if(mSingleDemo == null){
				mSingleDemo=new SingleDemo();
			}
			return mSingleDemo;
		}
			
	}




2.Handler使用不当造成的内存泄露
Handler造成的内存泄露在Android开发中是最常见的,我们知道,Handler,Message以及MessageQuene是相
互关联在一起的,万一Handler发送的Message未被处理,则该Message以及发送它的Handler对象都会一直
被MessageQuene持有。
可以通过弱引用和static内部类来防止内存泄露
	public class HandlerActivity extends AppCompatActivity{
		//声明为静态的内部类,因为非静态内部类会持有外部类的引用,有可能会造成内存泄露
		//声明为静态内部类后,其存活期就与activity的生命周期无关了
		private static final class MyHandler extends Handler{
			//不过倘若用到 Context 等外部类的 非static 对象,还是应该通过弱引用传入
			private final WeakReference<HandlerActivity> mActivity;

			
			@Override
			public void onHandlerMessage(Message msg){
				super(msg);
				HandlerActivity handlerActivity=mActivity.getActivity();
				if(handlerActivity!=null){
					//do something...
				}
				
			}
			
		}
		
		private MyHandler mMyhandler=new MyHandler(this);
		//匿名的静态内部类绝不会持有外部类的引用
		private static final Runnable RUNNABLE=new Runnable(){
			@Override
			public void run(){}
		}
	
		protect void onCreate(Bundle saveInstanceStates){
			super.onCreate(saveInstanceStates);
			setContentView(R.layout.activity_main);
			mMyhandler.postDelayed(RUNNABLE,500);
		}
	
	}


综述:推荐使用静态内部类+弱引用 WeakReference 这种方式,但要注意每次使用前判空。

这里再提下java的几种引用类型:StrongReference,SoftReference,WeakReference 和 PhatomReference:

回收时机 级别 用途 生存时间

StrongReference  绝不 强引用  对象的一般状态 JVM停止运行时终止
SoftReference 内存不足时 软引用 联合ReferenceQuene构造的有效期短/占内存大/声明周期长的对象的二级高速缓冲器(内存不足时清空) 内存不足时终止
WeakReference 在垃圾回收时    弱引用 联合ReferenceQuene构造的有效期短/占内存大/声明周期长的对象的一级高速缓冲器(系统发生gc则清空) gc运行后终止
PhatomReference 在垃圾回收时 虚引用 联合ReferenceQuene来跟踪对象被gc回收的活动 gc运行后终止

继续回到主题。前面所说的,创建一个 静态Handler内部类,然后对 Handler 持有的对象使用弱引用,这样在回收时也可以回收 Handler 持有的对象,
但是这样做虽然避免了 Activity 泄漏,不过 Looper 线程的消息队列中还是可能会有待处理的消息,所以我们在 Activity 的 Destroy 时或者 Stop 
时应该移除消息队列 MessageQueue 中的消息。
	@Override
	protected void onDestory(){
		super();
		mMyhandler.removeCallBacksAndMessages(Object token);
	}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值