强指针的引用就是为了解决下面一种情景:
对于上面情景,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,由于B在A中引用了不能被释放,反过来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
1、sp和wp是一个类,他们用来管理一个对象的生命周期,但是他们都是模本类,所有管理的对象都必须继承RefBase类,这个RefBase类叫做真实对象,就是管理对象本身。
2、RefBase类是最核心的类,他内部的一个weakref_impl内部类,继承weakref_type类,这个类我们一般叫做影子对象,和RefBase是相对应的。weakref_impl中有几个变量,mStrong用来记录对象的强引用计数,mWeak用来记录对象的弱引用计数,mBase是RefBase类型的,也就是需要管理对象本身。mFlag是采用哪种方式去管理对象的生命周期。
3、从2中我们可以看出来,RefBase和weakref_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语言却没有这个问题,为什么呢?因为java有GC,也就是垃圾回收而C++没有。C++的做法是:程序员必须做到在new一个对象之后当不需要使用它的时候必须delete这个对象。看来很好,没有问题是吧?但是,在实际的项目中,就是会有人忘记去delete这个对象,或者随意delete一个对象,导致依赖这个对象的别的模块发生野指针错误。这几乎是经常发生的,而且是很难避免的。
LightRefBase是轻量级的,那么RefBase就应该是重量级的了,它的名字中少了light。Android为神马要引入这个类呢?想一下这样一个场景,现在有两个对象:A和B,对象A中有B的引用,因此B的引用等于1;对象B中有A的引用,因此对象A的引用对于1;现在问题来了,这两个对象和外界的任何对象都没有关系,也就说除了A和B两者之间有关系,别人和他们都没有关系!现在他们就是多余的了,应该被销毁!但是由于A和B的引用计数都是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为我们所WP或SP引用的对像的基类,主要提供计数器功能,在构建一个对像时我们首先从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;
};WP跟SP一样我们主要分析构造函数和析构函数
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的时候才释放真实对像,同时释放影子对像。如果对一下对像是弱引用,要引用这个对像的变量,则需要把这个弱引用升级为强引用了才能操作无素,因为弱引用对像可能真实对像已经释放了。只是影子对像,这种情况是不能操作实际对像的了。只有影子对和真实对像都存在的时候才能操作这个对像里面的元素。