看了这么多年的博客,感觉也应该也做点啥,后期会不间断地整理分享各种知识点,共勉。
1 内存泄露?
① 如果一个对象不被任何引用所指向;
② 还有如果一组对象中只包含互相的引用,而没有来自它们外部的引用;
则该对象会在被GC发现的时候被回收。
2 产生以及处理 样例
Android开发中我们经常见到Handler、Runnable、AsyncTask等类,如果采用非静态内部类|匿名内部类的方式使用的话,都会隐式地持有外部类的引用。
在Java中非静态内部类 | 匿名内部类都默认持有外部类的引用,使用不当的话会使外部类一直被某对象持有引用,从而在其该被GC回收时却不被回收,最终导致了内存泄漏,严重后会出现 卡顿 直至崩溃,给用户带来不好的体验。
为啥会默认持有外部类的引用呢?
想象下,如果不隐式地持有外部类的引用,我们怎么可以在内部任意使用外部类的成员变量以及各种方法呢?所以说java在设计之初就有这种默认的规则。
3 解决思路
搞明白原因后就来思考下解决方案,两个方向:
①java中静态内部类不持有外部引用,采用静态内部类+弱引用(WeakReference)持有外部类实例,这样activity回收时WeakReference中的对象会及时回收。
至于静态内部类持有外部引用,可以从编译后的字节码文件中对比查验下:
源文件:
public class MyClass {
private class MyInnerClass {
private String innerString;
public MyInnerClass( ) {
}
public MyInnerClass(String innerString ) {
this.innerString = innerString;
}
}
}
编译后字节码文件:
class MyClass$MyInnerClass
{
private String innerString;
public MyClass$MyInnerClass(MyClass paramMyClass) {}
public MyClass$MyInnerClass(MyClass paramMyClass, String paramString)
{
this.innerString = paramString;
}
}
②代码中做好内存回收操作(把代码逻辑写好)
在销毁Activity service等的时候 停止各种异步队列耗时操作,切断他们之间相互持有引用的线。如线程的话停止掉,或者涉及handler的话,注意ondestory()之前调用removeCallbacksAndMessages(null)方法,移除回收消息队列的消息。
对比样例:
private static class MyTestHandler extends Handler {
WeakReference<Activity > mActivityReference;
MyTestHandler(Activity activity) {
mActivityReference= new WeakReference<Activity>(activity);
}
@Override
public void handleMessage(Message msg) {
final Activity activity = mActivityReference.get();
//注意非空判断
if (activity != null) {
......;
}
}
}
像上面只是涉及部分的样例,实际代码中还有很多地方可以做优化来防止内存泄露导致的手机卡顿、cpu耗比占高、过热、直至闪退崩溃。
本文深入探讨Android开发中常见的内存泄露问题,包括Handler、Runnable、AsyncTask等类的不当使用导致的外部类引用问题,以及如何通过静态内部类与弱引用(WeakReference)组合或在Activity销毁时进行内存回收操作来解决内存泄露。
905

被折叠的 条评论
为什么被折叠?



