列举内存泄漏

CSDN话题挑战赛第2期
参赛话题:面试宝典

1. 内部类

public class MyClass2 {
    public void out(){
        new Thread(){
            @Override
            public void run() {
            }
        };
    }
}
/**
编译后会产生两个class文件:MyClass2.class、MyClass2$1.class
*/
// MyClass2$1.class
class MyClass2$1 extends Thread {
    MyClass2$1(MyClass2 var1) {
        this.this$0 = var1; // 这个this$0就是隐式的引用外部类引用
    }

    public void run() {
    }
}

现象

  1. 为什么非静态内部类对外部类会存在一个隐式引用?
    • 内部类可以引用外部类的方法,因为省略了外部类.this,所以才会说非静态内部类对外部类会存在一个隐式引用
  2. 非静态内部类和非静态匿名内部类中确实都持有外部类的引用, 静态内部类中未持有外部类的引用。

解决方案

  1. 去除隐式引用(通过静态内部类来去除隐式引用)
  2. 手动管理对象引用(修改静态内部类的构造方式,手动引入其外部类引用)
  3. 当内存不可用时,不执行不可控代码(Android可以结合智能指针,WeakReference包裹外部类实例)

2. Service

如果通过 bindService 方式进行开启 Service,退出相应 Activity 后,没有 unbindService,则会有内存泄漏;
绑定的方式,通过ServiceConnection的方式进行绑定,如果没有解绑的话,Activity则会内存泄漏

private val conn = object : ServiceConnection{
	override fun onServiceConnected(name:ComponentName, service: IBinder) {
            LogUtil.v(simpleName, "service:$service")
            //连接后拿到 Binder,转换成 AIDL,在不同进程会返回个代理
            iPersonInterface = ManualBinder.asInterface(service)
            //            IAidlInterface iAidlInterface = AIDLBinder.asInterface(service);
            try {
                service.linkToDeath(mDeathRecipient, 0)
            } catch (e: RemoteException) {
                e.printStackTrace()
            }
        }
        override fun onServiceDisconnected(name: ComponentName) {
            iPersonInterface = null
        }
}

以及Service自身由于Binder的原因,Activity内存泄漏,持有Binder也不会被回收,从而也会造成Service自身内存泄漏

3. BroadcastReceiver

动态注册的广播,如果退出相应 Activity 后没有 unresiterReceiver,则会有内存泄漏;如果Receiver中有延迟操作,未能及时取消注册广播,也会造成Activity内存泄漏,进而造成Recevier内存泄漏

4. 线程泄漏

run方法中持有的外部类引用或关联对象,在它们需要退出时,未及时退出run方法,从而造成线程持有的相关引用未能及时释放,引发内存泄漏

5. 单例泄漏

由于单例类是一个单例模式,那么这个类的生命周期就伴随整个应用的生命周期,而它在被单例类创建的时候引用了Activity,所以当系统GC的时候试图去回收Activity时,发现它却在被另一个仍然在内存里的单例类所引用,所以GC回收它失败,从而导致了内存泄漏。

解决方案:对上述的 Activity(Context)属性使用弱引用即可;

6. 系统泄漏

InputMethodManager自身也会存在内存泄漏,解决方式如下

InputMethodManager im = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
try {
    //获得 所有属性  getField->public  以及父类
    Field mCurRootViewField = InputMethodManager.class.getDeclaredField("mCurRootView");
    //设置允许访问权限
    mCurRootViewField.setAccessible(true);
    // 指定对象上此字段表示的值
    Object mCurRootView = mCurRootViewField.get(im);
    if (null != mCurRootView){
        Context context = ((View) mCurRootView).getContext();
        if (context == this){
            //破怪gc 引用链
            mCurRootViewField.set(im,null);
        }
    }
} catch (NoSuchFieldException e) {
    e.printStackTrace();
} catch (IllegalAccessException e) {
    e.printStackTrace();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值