android sp和wp
android的sp是指strong pointer wp则是weak pointer,引入他们的目的是解决C++中容易出现的空指针、野指针、new 和 delete导致的内存泄漏或者访问出错问题。
无论时sp还是wp,其目标对象都需要继承refBase类,改为为其子类提供了引用计数变量mstrong 、mweak以及用于对变量进行操作的operation 函数;
对于sp指针,在创建是赋值或者new赋值时,会调用目标对象的incStrong函数,增加mstrong的引用计数,同时mweak也会加1:
sp<T> pA1 = new T
如上(frameworks/native/include/utils/StrongPointer.h):
(frameworks/native/libs/utils/RefBase.cpp):
而在已移除是会减1:
(frameworks/native/libs/utils/RefBase.cpp)发现计数为0后还会自动释放delete 对象:
那么wp的目的是什么呢,在有些场景下比如父类CDad持有子类CChild,同时CChild也持有CDad这个时候,引用计数mstrong不会变为0,这样就导致父类和子类一直无法释放,形成死锁,所以正对这种情况开发了wp,并约定父类使用sp,子类则使用wp,当mstrong计数为0时无论mweak是否为0,都可以delete目标对象(refbase子类)。不过如果这时候wp访问delete的目标对象就会放生访问越界,所以android规定wp必须升级为sp后才能访问目标对象。
看一下refbase在decWeak函数中,当mweak的计数为0是会有哪些动作:
首先mWeak 减1,如果c !=1 即mWeak不为0直接返回;
如果为0,进入下一步判断:
(impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG
如果为真,表示目标现在由强应用控制,需要mstrong为0是释放对象,但是
mpl->mStrong == INITIAL_STRONG_VALUE
如上表明从未有过强引用,那么此时需要释放对象delete mbase,否者只需要释放
weakref_impl这个计数器
如果if ((impl->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK)为真
此时为wp控制,则释放目标对象:
这个mflags目前来看在初始化时都为0也就是 OBJECT_LIFETIME_STRONG,android提供了函数修改这个值extendObjectLifetime:
如下是wp/sp与refbase的类图,可以参考理解:
问题:
前面提到在decWeak函数中,mWeak计数为0时,在强引用下,且强引用不为0时,会delete impl,这个impl应该是refbase中的mRefs:
如果在这边释放,在使用refBase中的decStrong去释放mBase的时候也使用该变量
这样访问的不就是一个不存在的内存区域吗,应该会crash吧!
能够避免该问题,就需要mWeak的计数值只能比mStrong大,不能小;
就目前代码来看,在incStrong是同时会增加mWeak、mStrong,但是incWeak时只会增加mWeak,这么看来mWeak的计数值只会比mStrong大,不会小,那么就不会出现这样的crash。
那为什么一定要在decWeak去释放mRefs呢,看一下RefBase的析构函数,mWeak =0 才能delete mRefs ,不得不说android的工程师真是NB: