Android 智能指针

Android 智能指针

 

1. 由来

为了解决C++指针使用过程中遇到的内存泄漏无效引用问题,Android 系统引入了智能指针。

智能指针是一种能够自动维护对象引用计数的技术。智能指针是一个对象,而不是一个指针,但是它引用了一个实际使用的对象。正是因为它是一个对象,因此它能够自动地维护实际对象的引用计数。简单来说:

  • 在智能指针构造时,就增加它所引用的对象的引用计数。
  • 在智能指针析构时,就减少它所引用的对象的引用计数。

由于C++中智能指针的构造函数和析构函数都是自动执行的,因此,它就很自然的实现了自动的对象引用计数技术。

为了解决引用计数器的归属问题,计数器只能由实际使用的对象(被智能指针引用的目标对象)自身持有。

为了解决释放时相互引用的问题,需要明确引用关系的强和弱,即需要区分对象的强引用计数和弱引用计数,并且规定对象的生命周期应该受强引用控制,这样可以打破这种循环引用的带来的问题。

2.  类别和原理分析

智能指针分为三类:

  • 轻量级指针(Light Pointer)

       轻量级指针通过简单的引用计数技术来维护对象的生命周期。如果一个类的对象支持轻量级指针,那么它必须从LightRefBase类继承下来,因为LightRefBase类提供了一个简单的引用计数器。LightRefBase类只有一个成员变量mCount,用来描述一个对象的引用计数值。LightRefBase类同时提供了成员函数incStrong和decStrong来增加和减少它所引用的对象的引用计数。在成员函数decStrong中,如果对象的引用计数值在减少之后变成0,那么就表示需要释放这个对象所占用的内存了。

  • 强指针(Strong Pointer)

      强指针通过强引用计数来维护对象的生命周期。如果一个类的对象要支持强指针,那么它就必须从RefBase类继承下来,因为RefBase类提供了强引用计数器和弱引用计数器。

      RefBase类与LightRefBase类不一样的是,它不是直接使用一个整数来维护对象的引用计数的,而是使用一个weakref_impl对象,及成员变量mRefs来描述对象的引用计数。 weakref_impl类同时为对象提供了强引用计数和弱引用计数,它的源码如下所示(/system/core/libutils/RefBase.cpp)

      weakref_impl类继承了weakref_type类。weakref_type类定义在RefBase类的内部,它提供了成员函数incWeak、decWeak、attemptIncStrong和attemptIncWeak来维护对象的强引用计数和弱引用计数。weakref_type类只定义了引用计数维护接口,具体的实现是由weakref_impl类提供的。 weakref_impl类有两个成员变量mStrong和mWeak,分别用了描述对象的强引用计数和弱引用计数。同时,weakref_impl类的成员变量mBase指向了它所引用的对象的地址,而成员变量mFlags是一个标志值,用了描述对象的生命周期控制方式。 weakref_impl类的成员变量mFlags的取值范围为0和OBJECT_LIEFTIME_WEAK。其中:

0:表示对象的生命周期只受强引用计数的影响。

OBJECT_LIFETIME_WEAK:表示对象的生命周期同时受强引用计数和弱引用计数影响 。

所以可以得出结论:

    (1)如果一个对象的生命周期控制标志值被设置为0,那么只要它的强引用计数值为0,系统就会自动释放这个对象。

    (2)如果 一个对象的生命周期控制标志值被设置为OBJECT_LIFETIME_WEAK,那么只有当它的强引用计数值和弱引用计数值都为0时,系统才会释放掉这个对象。

  • 弱指针(Weak Pointer)

      如果一个类的对象支持使用弱指针,那么这个类就必须要从RefBase类继承下来,因为RefBase类提供了弱引用计数器。

      与强指针sp类类似,弱指针类wp也有一个成员变量m_ptr,用来指向它所引用的对象,但是弱指针类wp还使用另外一个类型为weakref_type*的成员变量m_refs,用来维护对象的弱引用计数。 

       因为弱指针所引用的对象可能是不受弱引用计数控制的,即它所引用的对象可能是一个无效的对象,且弱指针没有重载->,* 等运算符,所以不能通过弱指针直接操作它所引用的对象。如果需要操作一个弱指针所引用的对象,那么就需要将这个弱指针升级为强指针,这是通过调用它的成员函数promote来实现的。如果升级成功,就说明该弱指针所引用的对象还没有被销毁,可以正常使用。

一个弱指针所引用的对象可能处于两种状态:

第一种:该对象同时也被其他强指针对象所引用,此时可以安全地将这个弱指针升级为强指针。

第二种:该对象没有被任何强指针引用。这里情况就比较复杂了。需要根据对象生命周期来判断

     1. 如果对象生命周期只受强引用计数影响,那么就可以成功将该弱指针升级为强指针。因为它受强引用计数影响,而  此时该对象又没有被强指针引用过,那么它必然不会被释放。

     2. 如果只受弱引用计数影响,首先我们可以确定对象现在一定是存在的,因为现在有一个弱指针引用它。但是,这种情况需要进一步调用对象的成员函数onIncStrongAttempted来确认对象是否允许强指针引用它。如果返回为true说明允许则成功将该弱指针升级为强指针。如果返回为false,则说明升级失败。

 

其他参考资料:

https://blog.csdn.net/wzy_1988/article/details/43736137

https://www.jianshu.com/p/f131b299df66

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值