android智能指针之强指针和弱指针

强指针的引用就是为了解决下面一种情景:

对于上面情景,AB对像的代码关系可以表述如下:

Class A:public LightRefbase{

 Class B *b;

}

Class B:public LightRefbase{

 Class A *a;

}

Int main(){

/*下面是正常人的写法,会有问题因为AB释放时没有去判断AB是否被其它变量引用了.不能智能判断AB是否被引用,不能下面的定法。*

/*Class A *superyangA=new A();//superyangA.count=1

Class B *superyangB=new B();superyangB.count=1

superyangA->b=superyangB;//superyangB.count=2

superyangB->a=superyangA;//superyangA.count=2*/

/*下面是用轻量级指针来写的*/

Class sp<A> superyangA=new A();//superyangA.count=1

Class sp<B> superyangB=new B();superyangB.count=1

superyangA.m_ptr->b=superyangB;//superyangB.count=2

superyangB.m_ptr->a=superyangA;//superyangA.count=2

 

//退出main时首先系统会来释放superyangB,然后再来释放superyangA,由于BA中引用了不能被释放,反过来A又在B中引用了也不能被释放。这要就导致内存泄露了。

}

轻量级指针针对这个问题就无能力了,这样导致superayngA superyangB对像最后都不能释放,因此引入C++更高级的智能指针强指针和弱指针来解决这种情况。当用这种技术时我们大胆的猜想处理方法。对AB只做一个强指针调用,内部调用都用弱指针。这儿个时当后析构时,我们让AB都是强指针确定生命周期,最后强调用为1弱调用为2(强调用+1弱调用也会同时+1),由于为1就会释放对像。假如生命周期是弱指针确定生命周期,则AB都会保留一个弱指针,而不释放对像。对于这种猜想我们下方做仔细分析。针对轻量级指针和强指针或弱指针都是针对SP WP对像在析构时去释放所引用的对像。Android中的智能指针是对C++中的对象回收机制的封装,内部实现也很简单,就是用两个变量来控制,一个是强引用计数变量,一个是弱引用计数变量,这两个变量都是int类型的,表示一个对象被引用多少次,两个变量会依据具体的生命管理周期模式来决定是否释放对象

 

强指针弱指针引用的对像的所所使用的公共基类图如下:

 

安桌中用到一些原子操作函数:

函数android_atomic_inc的返回值是对像原来的强引用计数值,既加1前的值。

函数android_atomic_dec的返回值是对像原来的强引用计数值,既减1前的值。

一个对像的弱引用计数一定是大于或者等于它的强引用计数的

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

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

弱指针与强指针有一个很大的区别,就是弱指针不可以直接操作它所引用的对像,因为它所引用的对像可能不受弱引用计数控制的。既它所引用的对像可能是一个无效的对像,因此,如果需要操作一个弱指针所引用的对像,那么就需要将这个弱指针升级为强指针,这是通过调它的成员函数来实现的。如果升级成功,就说明该弱指针所引用的对像还没有被销掉,可以正常使用。

WP类是如何使得一人弱指针不能直接操作它所引用的对像的呢?,秘密就在于WP类没有重载*->操作符号,因此,我们就不能直接操作它所引用的对像。

Android_atomic_cmpxchg是一个与CPU体系结构相关的函数,在某些提供了特殊指令的体系结构中,函数android_atomic_cmpxchg委行原子性的加1操作效率会比函数android_atomic_inc高一些。

参考博客:http://www.2cto.com/kf/201605/505391.html

          :http://www.2cto.com/kf/201606/519710.html

1spwp是一个类,他们用来管理一个对象的生命周期,但是他们都是模本类,所有管理的对象都必须继承RefBase类,这个RefBase类叫做真实对象,就是管理对象本身。

2RefBase类是最核心的类,他内部的一个weakref_impl内部类,继承weakref_type类,这个类我们一般叫做影子对象,和RefBase是相对应的。weakref_impl中有几个变量,mStrong用来记录对象的强引用计数,mWeak用来记录对象的弱引用计数,mBaseRefBase类型的,也就是需要管理对象本身。mFlag是采用哪种方式去管理对象的生命周期。

3、从2中我们可以看出来,RefBaseweakref_impl这两个类是相互依赖的,而且他们也是相互对应的,一个是真实的对象,一个是影子对象。

 

 

弱引用计数是关系影子对象的,如果弱引用计数为0,那么影子对象一定要释放,但是真实对象不一定要释放
强引用计数是关系真实对象的,如果强引用计数为0,那么真实对象一定要释放的,但是影子对象不一定释放

decStrong方法主要做:就是看看是否要释放真实对象,因为强引用和真实对象关联的

RefBase的析构方法:真实对象被销毁的时候,需要做一个工作就是释放影子对象

释放影子对象有两个场景:
1)、如果强引用计数根本没有被使用过,那么直接释放
2)、如果强引用计数使用过,但是采用的是非强生命周期管理方式,也是释放

[如果是采用强生命周期管理对象的话,只有当强引用计数为0的时候,才会删除真实对象,当弱引用计数为0的时候,去删除影子对象。如果采用弱生命周期管理对象的话,只有当强引用计数和弱引用计数都为0的时候,才会删除真实对象。]这一段是智能指针的生命所在,也是我们能正确使用的关键点所在

关于智能指针的三种生命周期管理方式:

1. 如果对象的标志位被设置为0,那么只要发现对象的强引用计数值为0,那就会自动delete掉这个对象;
2. 如果对象的标志位被设置为OBJECT_LIFETIME_WEAK,那么只有当对象的强引用计数和弱引用计数都为0的时候,才会 自动delete掉这个对象;
3. 如果对象的标志位被设置为OBJECT_LIFETIME_FOREVER,那么对象就永远不会自动被delete掉,谁new出来的对象谁 来delete掉。

wp升级到sp才能使用真实对象,那么这里需要注意的是,如果真实对象已经delete了,那么wp升级sp之后的对象是为NULL的。

长久以来,C++中的内存管理问题一直让人头疼,空指针,野指针,内存泄露。。。。。。C++程序员看到这样的问题就是各种头大!这样的问题往往很难解决,尤其是代码架构比较庞大或者复杂的时候。但是同样是面向对象的JAVA语言却没有这个问题,为什么呢?因为javaGC,也就是垃圾回收而C++没有。C++的做法是:程序员必须做到在new一个对象之后当不需要使用它的时候必须delete这个对象。看来很好,没有问题是吧?但是,在实际的项目中,就是会有人忘记去delete这个对象,或者随意delete一个对象,导致依赖这个对象的别的模块发生野指针错误。这几乎是经常发生的,而且是很难避免的。

LightRefBase是轻量级的,那么RefBase就应该是重量级的了,它的名字中少了lightAndroid为神马要引入这个类呢?想一下这样一个场景,现在有两个对象:AB,对象A中有B的引用,因此B的引用等于1;对象B中有A的引用,因此对象A的引用对于1;现在问题来了,这两个对象和外界的任何对象都没有关系,也就说除了AB两者之间有关系,别人和他们都没有关系!现在他们就是多余的了,应该被销毁!但是由于AB的引用计数都是1,不为0,因此使用我们上面的方案解决不了了!还是会有内存泄露问题!怎么办呢??解决的办法是这样的,将引用分类,分为两类:强引用和弱引用。强引用就是我们上面使用的那种,弱引用是什么呢?弱引用从字面上引用的力度比强引用要弱,事实确实是这样。弱引用弱在哪里呢?弱在保证使用对象的可靠性上。这么说有点抽象,具体来说吧,像上面说的那个问题,如果A对象对B对象的引用是强引用的话,那么B对象对A对象必须是弱引用,否则还有刚才说的循环引用的问题。对象的销毁,关注的是对象的强引用,而不是对象的弱引用,也就是说如果对象的强引用为0的话不管对象的弱引用是多少直接delete!这就是弱引用弱的地方,也就是说你想使用的对象不一定存在呢!!另外,还有一个问题,那就是既然对象可能不存了,弱引用怎么使用这个对象呢?面对这个问题,有这样一个规定:

1. 弱引用在使用之前不如先升级为强引用才行。

如果对象不存在了,那么升级弱引用是失败的,自然就可以避免引用对象存在不确定性的问题了。

如果对像A对对像B是强引用,那么B则一定只能是弱引用A否则解决不了AB循环嵌套问题

 

强指针弱指针的常用类分析:

--------------------------------------------------------------------------------------------------------------

RefBase-

weakref_type

class RefBase::weakref_impl : public RefBase::weakref_type

weakref_impl* const mRefs;

-------------------------------------------------------------------------------------------------------------

 WP-

T*              m_ptr;

    weakref_type*   m_refs;

--------------------------------------------------------------------------------------------------------------

 SP-

  T* m_ptr;

--------------------------------------------------------------------------------------------------------------

RefBase为我们所WPSP引用的对像的基类,主要提供计数器功能,在构建一个对像时我们首先从wp sp的构造函数入首 先后分别是其对应的析构函数。

 

强指针类里面有很多成员我们主要分析构造函数和析构函数

class sp{

 inline sp() : m_ptr(0) { }

  sp(T* other);

  sp(const sp<T>& other);

  ~sp();

中间部分省略

 

 T* m_ptr;

}

template<typename T>

sp<T>::sp(T* other)

: m_ptr(other)

  {

    if (other) other->incStrong(this);

  }

这是SP的构造函数调用incStrong增加对像T中的强引用计数值

template<typename T>

sp<T>::~sp()

{

    if (m_ptr) m_ptr->decStrong(this);

}对应的这个函数就是减少强引用计算值

template <typename T>

class wp

{   

inline wp() : m_ptr(0) { }

  wp(T* other);

  ~wp();

 T*              m_ptr;

    weakref_type*   m_refs;

};WPSP一样我们主要分析构造函数和析构函数

template<typename T>

wp<T>::wp(T* other)

    : m_ptr(other)

{

    if (other) m_refs = other->createWeak(this);

}减少弱引用计数

 

template<typename T>

wp<T>::~wp()

{

    if (m_ptr) m_refs->decWeak(this);

}

那么我们下面应该来分析这个函数

incStrong:强引用计数值加1

decStrong:强引用计算值减1

createWeak

decWeak弱引用计算减1

同时还要分析RefBase的构造函数和析构函数

上面6个函数就是我们下面分析的重点也是强用引用弱引用的重点。

RefBase::weakref_type* RefBase::createWeak(const void* id) const

{

    mRefs->incWeak(id);

    return mRefs;

}弱引用计算值加1

RefBase::~RefBase()主要用来释放影子变量mRefs

对于强指针 弱指针的应用我们主要清楚上面函数的调用关系既可 要明白指针的计数值的用处。对像的生命周期由什么决定,如果由强指针决定,如果强应用为0了则要释放真实对像,保留影子对像。如果对像由弱指针决,只当弱引用计数为0的同时强引用也为0的时候才释放真实对像,同时释放影子对像。如果对一下对像是弱引用,要引用这个对像的变量,则需要把这个弱引用升级为强引用了才能操作无素,因为弱引用对像可能真实对像已经释放了。只是影子对像,这种情况是不能操作实际对像的了。只有影子对和真实对像都存在的时候才能操作这个对像里面的元素。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值