• android linkToDeath内存泄露分析



    Register the recipient for a notification if this binder goes away. //注册binder死亡的通知

    public void linkToDeath(@NonNull DeathRecipient recipient, int flags) throws RemoteException;

    现场复现

    提供给三方应用的sdk中的实现,而对外提供的是一个Manager 单例

    private final IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
        @Override
        public void binderDied() {
            bindService(); //在service死亡的时候重新拉起保活
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    发现三方应用actiivty在销毁后有内存泄漏,持有引用的是deathReceipent

    private final ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
           
            try {
                iBinder.linkToDeath(mDeathRecipient, 0);
            } catch (Throwable e) {
                Log.e(TAG, "linkToDeath fail : ", e);
            }
        }
    ​​​​​​​}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    这里service重新链接的时候,之前已经链接的java对象iBinder会被回收,而注册到iBinder的deathRecipient没有被回收导致内存泄漏

    ​​​​​​​

    ​疑问

    ​​​​​​​iBinder释放的时候是否是unlink DeathRecipient,如果主动释放就不会存在内存泄漏的问题

    BinderProxy.java

    ​​​​​        public static final long sNativeFinalizer = getNativeFinalizer();
            /* Returns the native free function 随java对象一起释放的native对象 */
            private static native long getNativeFinalizer();
            public static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
                    BinderProxy.class.getClassLoader(), sNativeFinalizer, NATIVE_ALLOCATION_SIZE);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    frameworks/base/core/jni/android_util_Binder.cpp

    JNIEXPORT jlong JNICALL android_os_BinderProxy_getNativeFinalizer(JNIEnv*, jclass) {
        return (jlong) BinderProxy_destroy;
    }
    static void BinderProxy_destroy(void* rawNativeData)
    {
        BinderProxyNativeData * nativeData = (BinderProxyNativeData *) rawNativeData;
        LOGDEATH("Destroying BinderProxy: binder=%p drl=%p\n",
                nativeData->mObject.get(), nativeData->mOrgue.get());
        delete nativeData;
        IPCThreadState::self()->flushCommands();
        --gNumProxies;
    }
    
    struct BinderProxyNativeData {
        // Both fields are constant and not null once javaObjectForIBinder returns this as
        // part of a BinderProxy.
    
        // The native IBinder proxied by this BinderProxy.
        sp<IBinder> mObject;
    
        // Death recipients for mObject. Reference counted only because DeathRecipients
        // hold a weak reference that can be temporarily promoted.
        sp<DeathRecipientList> mOrgue;  // Death recipients for mObject.
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    如上,iBinder销毁只是简单调用了BinderProxyNativeData析构函数,并没有将JavaDeathRecipient从List中移除,

    如果发现binderProxy销毁了,并且List不为空,则会发出内存泄露警告

    DeathRecipientList::~DeathRecipientList() {
        LOGDEATH("Destroy DRL @ %p", this);
        AutoMutex _l(mLock);
    
        // Should never happen -- the JavaDeathRecipient objects that have added themselves
        // to the list are holding references on the list object.  Only when they are torn
        // down can the list header be destroyed.
        if (mList.size() > 0) {
            List< sp<JavaDeathRecipient> >::iterator iter;
            for (iter = mList.begin(); iter != mList.end(); iter++) {
                (*iter)->warnIfStillLive();
            }
        }
    }
    class JavaDeathRecipient : public IBinder::DeathRecipient
    {
    public:
        JavaDeathRecipient(JNIEnv* env, jobject object, const sp<DeathRecipientList>& list)
            : mVM(jnienv_to_javavm(env)), mObject(env->NewGlobalRef(object)),
              mObjectWeak(NULL), mList(list)
        {
            // These objects manage their own lifetimes so are responsible for final bookkeeping.
            // The list holds a strong reference to this object.
            LOGDEATH("Adding JDR %p to DRL %p", this, list.get());
            list->add(this);
    
            gNumDeathRefsCreated.fetch_add(1, std::memory_order_relaxed);
            gcIfManyNewRefs(env);
        } 
        
        void clearReference()
        {
            sp<DeathRecipientList> list = mList.promote();
            if (list != NULL) {
                LOGDEATH("Removing JDR %p from DRL %p", this, list.get());
                list->remove(this);
            } else {
                LOGDEATH("clearReference() on JDR %p but DRL wp purged", this);
            }
        }
    
        void warnIfStillLive() {
            if (mObject != NULL) {
                // Okay, something is wrong -- we have a hard reference to a live death
                // recipient on the VM side, but the list is being torn down.
                JNIEnv* env = javavm_to_jnienv(mVM);
                ScopedLocalRef<jclass> objClassRef(env, env->GetObjectClass(mObject));
                ScopedLocalRef<jstring> nameRef(env,
                        (jstring) env->CallObjectMethod(objClassRef.get(), gClassOffsets.mGetName));
                ScopedUtfChars nameUtf(env, nameRef.get());
                if (nameUtf.c_str() != NULL) {
                    ALOGW("BinderProxy is being destroyed but the application did not call "
                            "unlinkToDeath to unlink all of its death recipients beforehand.  "
                            "Releasing leaked death recipient: %s", nameUtf.c_str());
                } else {
                    ALOGW("BinderProxy being destroyed; unable to get DR object name");
                    env->ExceptionClear();
                }
            }
        }
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62

    List添加是在JavaDeathRecipient构造函数中, 移除只有在unlinkToDeath的时候调用clearReference会从list中移除

    static jboolean android_os_BinderProxy_unlinkToDeath(JNIEnv* env, jobject obj,
                                                     jobject recipient, jint flags)
    {
        jboolean res = JNI_FALSE;
        if (recipient == NULL) {
            jniThrowNullPointerException(env, NULL);
            return res;
        }
    
        BinderProxyNativeData* nd = getBPNativeData(env, obj);
        IBinder* target = nd->mObject.get();
        if (target == NULL) {
            ALOGW("Binder has been finalized when calling linkToDeath() with recip=%p)\n", recipient);
            return JNI_FALSE;
        }
    
        LOGDEATH("unlinkToDeath: binder=%p recipient=%p\n", target, recipient);
    
        if (!target->localBinder()) {
            status_t err = NAME_NOT_FOUND;
    
            // If we find the matching recipient, proceed to unlink using that
            DeathRecipientList* list = nd->mOrgue.get();
            sp<JavaDeathRecipient> origJDR = list->find(recipient);
            LOGDEATH("   unlink found list %p and JDR %p", list, origJDR.get());
            if (origJDR != NULL) {
                wp<IBinder::DeathRecipient> dr;
                err = target->unlinkToDeath(origJDR, NULL, flags, &dr);
                if (err == NO_ERROR && dr != NULL) {
                    sp<IBinder::DeathRecipient> sdr = dr.promote();
                    JavaDeathRecipient* jdr = static_cast<JavaDeathRecipient*>(sdr.get());
                    if (jdr != NULL) {
                        jdr->clearReference();//从list中移除
                    }
                }
            }
    
            if (err == NO_ERROR || err == DEAD_OBJECT) {
                res = JNI_TRUE;
            } else {
                jniThrowException(env, "java/util/NoSuchElementException",
                                  base::StringPrintf("Death link does not exist (%s)",
                                                     statusToString(err).c_str())
                                          .c_str());
            }
        }
    
        return res;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    解决方案

    在收到binderDied通知后主动调用unlinkToDeath

    private static class DeathRecipient implements IBinder.DeathRecipient {
        private IBinder mBinder;
        private Manager mManager;
    
        public DeathRecipient(IBinder iBinder, Manager manager) {
            mBinder = iBinder;
            mManager = manager;
        }
    
        @Override
        public void binderDied() {
            mBinder.unlinkToDeath(this, 0);
            mManager.bindService();
        }
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
  • 相关阅读:
    Pytorch疑难小实验:理解torch.cat()在不同维度下的连接方式
    线上发生锁表怎么办 show processlist命令详解
    搭建ELK+Filebead+zookeeper+kafka实验(详细版)
    openpnp - src - 配置文件载入过程的初步分析
    SpringBoot如何实现全局异常类处理
    About Stacked Generalization
    Java开发者的神经网络进阶指南:深入探讨交叉熵损失函数
    Springboot初步开发网站(不接数据库,简单增删改查实现)
    了解Java反射原理(反射篇 一)
    Mysql词法分析实验(一)
  • 原文地址:https://blog.csdn.net/congqingbin/article/details/132868140