Understanding Android Source: RefBase, wp, sp

管理对象生命周期,常常会采用引用计数技术。当有一个新的指针指向了一个对象时,这个对象的引用计数就增加1;相反,当一个指针不再指向一个对象时,这个对象的引用计数就减少1。而当对象的引用计数减少为0时,它所占用的内存就可以被安全地释放了。

上述方案可以应对大部分使用场景,但是,对于相互引用的情况,却无能为力。比如,两个对象A和B,A引用了B,同时B也引用了A。在任何时间,它们都被对方引用着,以致于无法被释放。对此,一般做法是通过强、弱引用计数予以解决。将有关联的对象划分为“父-子”和“子-父”关系。在前者中,“父”对象通过强引用计数来引用“子”对象;在后者中,“子”对象通过弱引用计数来引用“父”对象。

举例,对象A和对象B是“父-子”关系,则对象B和对象A就是“子-父”关系。对象A通过强引用计数来引用对象B,而对象B通过弱引用计数来引用对象A。当对象A不再使用时,由于对象B是通过弱引用计数来引用它的,因此对象A的生命周期不受对象B的影响,此时对象A可以被安全释放。在释放对象A时,同时也释放它对对象B的强引用计数,因此,对象B也不再被强引用,其可以安全地释放了。

这里需要说明的是,当对象B要使用对象A时,由于是弱引用关系,因此,对象A有可能已经被释放了。因此,对象B不能直接使用对象A,而是要将对象B持有的对对象A的弱引用计数,升级为强引用计数。如果升级失败,则说明对象A已经被释放了。

Smart Pointer

Smart Pointer

Android系统提供的智能指针(Smart Pointer)正是上述技术的一种实现。其能够自动维护对象的引用计数。在智能指针构造时,增加它所引用的对象的引用计数;在智能指针析构时,减少它所引用的对象的引用计数。这里需要说明的是,智能指针并非是一个寻常的指针,意思是其引用了一个实际使用的对象。

Android提供了一个公共类,即RefBase,所有支持使用智能指针的对象类都必须要从这个公共类继承下来。这样,Android系统的智能指针就可以通过这个引用计数器来维护对象的生命周期。RefBase使用一个weakref_impl,来描述对象的引用计数。weakref_type定义了对象的强、弱引用计数接口,具体实现由weakref_impl提供,后者继承了前者。

SP Construct

SP Construct

同时,Android也提供了sp和wp两个模板类,来实现强弱引用。创建一个sp时,则增加强引用计数时,而此时弱引用计数一定也会被增加,但是,反之则不然。当一个对象的弱引用计数为0时,其强引用计数则一定为0。当强引用计数为0时,弱引用可能还大于0,此时只能将对应的RefBase对象释放掉,而不能将其内部的weakref_impl也释放掉。只有在弱引用技术也为0的前提下,weakref_impl才会被释放。

SP Destory

SP Destory

一个wp所引用的对象可能处于两种状态,其一,该对象也正在被其他强指针所引用,此时,其强引用计数值大于0,并且不等于初始值。其二,该对象没有被任何强指针引用,此时,又细分为两种情况,要么它没从来被强指针引用过,即其强引用计数数值等于初始值,要么它曾被强指针引用过,但已经全部释放了,即其强应用计数数值等于0。

WP Destory

WP Destory

如前文所述,wp和sp的不同在于,前者不可以直接操作它所引用的对象,因为这个对象可能不受弱引用计数控制,可能是个无效的对象。如果想要操作一个弱指针引用的对象,则必须提升其为强指针。这样就需要通过promote函数来完成。

将弱指针提升为强指针,并非一定会成功,比如,目标对象已经被释放了,或者目标对象不允许强指针使用它,都会导致提升失败。可以通过重写对象的成员函数onIncStrongAttempted,决定了是否将弱指针升级为强指针。

Leave a comment

Your comment