内存泄露:
java中的垃圾(GC),垃圾回收的机制受java虚拟机的控制。java虚拟机会不定时的执行 System.gc();
一个本该被回收的对象A,被一个生命周期还没有完成的对象B所持有,导致该被回收的对象A无法被回收。
那么由于B对A的持有,导致了内存泄露。
PS:
对象没有在该释放的时候被释放。
android 中使用handler ,用作消息的传递。
1.在持有handler对象的类内部调用。
class A{
private String temp="hander问题";
private Handler handle=new Handler(){
// handleMessage
};
}
handler 作为内部类,在进行信息传递的时候,handler对象一直存在。当此时持有对象A的一个activity,或者fragment被用户销毁的时候。
对象A在垃圾回收机制运行的时候,发现Activity还被其他对象所持有(对象A中还有对象正在运行) 。
那此时handler的存在就导致了内存泄露。
class MyActivity extends Activity{
private A a= new A();
}
那这种内存泄露如何解决?
问题出在activity销毁的时候,跟他有关的都要销毁,class A ,内部handler 都要销毁。
可以在activity中的销毁的时候,给class A一个消息,(调用函数,回调函数,以及其他的消息传递)将handler内部的what移除。
mHandler.removeMessages(WhatConstants.AUDIO.DOWNLOAD_AUDIO_DONE);
mHandler=null;
现将message的标示移除,然后将handler赋值为空。垃圾回收机制再次完成的时候,activity->A->handler 的持有链就会被回收。
实际场景:
在项目遇到这种情况:
class A extends View {
private Handler handle=new Handler(){
// handleMessage
};
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mHandler.removeMessages(WhatConstants.AUDIO.DOWNLOAD_AUDIO_FILED);
mHandler=null;
}
}
当这样初始化handler的时候,android studio 会提示这样的warning
自己翻译:
如果你这样声明一个handler作为内部类,当垃圾回收机制运行的时候,这个handler就会阻止外部调用类(class A)被垃圾回收掉。
如果这个handler被looper或者MessageQueue 在主线程以外的其他现成中使用,就不会出现问题。但是当个handler被looper或者MessageQueue 在主线程使用,你就需要对这个handler的声明进行处理。像下面这样:
1.声明这个handler作为内部类.(可行,不会出现声明周期的问题)
2.外部类,当你声明这个handler的时候,使用WeakReference(弱引用) 来初始化你的handler,在使用成员class A 的成员变量的时候,使用这个WeakReference。
WeakReference: 当声明一个类采用弱引用的方式进行声明,当垃圾回收机制运行的时候,垃圾回收机制会无视 handler对class A 的持有。直接回收class A。
WeakReference:详细解释—》》》http://www.tuicool.com/articles/imyueq
可是按提示的说法是怎么用的呢 ?
private MyHandler myHandler= new MyHandler(this);
private class MyHandler extends Handler{
WeakReference<A> weakReference;
public MyHandler(A a){
weakReference=new WeakReference<A>(a);
}
@Override
public void handleMessage(Message msg) {
A a= WeakReference.get();
super.handleMessage(msg);
switch (msg.what){
Log.d("~~~", a.temp);
}
}
}
这种情况下,当activity销毁的时候,由于handler持有class A 的弱引用 ,activity->A->handler中的activity ,class A 都会被回收。
此时 这种情况虽然解决了内存泄露,又会出现另外一种问题。
!!!!如果handler的生命周期还没有完成呢?<~~~~会崩溃的, crash>
因为handler已经为空了,null.
所有还是需要当activity 被销毁的时候,给class A 一个消息,移除handler中正在执行的任务,移除handler中的message.what。并将handler==null;
在继承了view对象的Class A中有一个方法,
onDetachedFromWindow
这个方法的意思是,当view与activity之间解除关系的时候,会调用这个方法。(如果使用view的时候,完成上述的内存泄露问题的时候,这是一个神技)。也就是activity 给class A 一个消息。
直接在这个方法中对handler正在进行的操作进行处理。一切都是那么的优美。
问题也就妥妥的解决了。
关于内存泄露还会有更多的场景。此处只是在开发中遇到一个场景。但是也具有一般性。
项目中内存泄露的检测:这里给大家推荐一个神器,但是具体的用法还是不熟练。
https://github.com/liaohuqiu/leakcanary-demo
中文讲解:
http://www.liaohuqiu.net/cn/posts/leak-canary-read-me/
关于内存泄露其他高人的博客
http://www.linuxidc.com/Linux/2013-12/94065.htm
欢迎大家交流~