轻量级指针在Android中是由LightRefBase来提供的,看下内容:
一个类只要继承LightRefBase,然后配合sp就可以使用智能指针的功能了。sp后面会单独介绍。
从这儿可以看出来,轻量级指针主要是在类里面添加了一个原子变量作为计数变量,然后通过incStrong和decStrong来实现计数的增减。
这儿有一个细节是这个计数可能会在多个线程里面访问,因此就会出现并发问题。比如一个对象对应的多个智能指针在多个线程里面使用,这时候就需要某个机制可以保证计数的准确。具体的策略就在incStrong和decStong里面,可以看到主要是使用了原子操作,并指定了内存序。这样通过内存屏障手段实现了不用持锁也能实现一致性。
接下来看下sp,一个类继承了LightRefBase后就拥有了智能指针计数机制,然后通过sp来操作指针才能实现智能管理内存的效果:
可以看到sp定义了对指针的基本操作,并通过m_ptr保存所管理的对象指针,看下构造和析构方法:
初始化m_ptr,然后调用incStrong增加计数,其实就是调用LightRefBase的incStrong,再看下移动拷贝构造函数:
移动只涉及拥有权的转移,因此不能更新计数。
其他构造函数也类似,再看下析构函数:
析构就是减少计数,调用LightRefBase的decStrong,看下对应的实现:
对计数减1,如果计数已经是1了,难么减少后就是0,就需要调用下析构,把对象释放掉。
强指针和弱指针对应的结构都是RefBase:
可以看到对于强指针,并不是简单用一个原子变量来计数了,而是使用了weakref_impl,这是一个weakref_type类型,定义如下:
可以看到RefBase提供了更多的能力,一个类继承了RefBase就可以通过强指针和弱指针来使用了。强指针就是前面提到的sp,关键的还是incStrong和decStrong,现在再看下流程, 对于sp的incStorng,调用的是RefBase的incStrong
可以看到先增加了弱引用,然后又添加了强引用,不过这儿并不是增加计数,而是记录引用指针,接下来才是增加计数,如果不是首次增加就直接返回了,否则会调用onFirstRef。这样如果有类想在第一次被引用的时候做些逻辑就可以使用这个机制了。
接下来看下incWeak和addStrongRef:
看到这儿基本就把添加引用流程走完了,从这儿也可以看出来弱引用计数一定大于等于强引用计数。
再看下decStrong,调用的也是RefBase的decStrong
可以看到decStrong中的逻辑主要就是操作强引用计数和弱引用计数。再看下移除引用和减少弱引用的实现:
再看下减少弱引用实现:
到了这儿decStrong流程就结束了,主要就是减少强弱引用计数的值,并且在引用计数为0时按照对象管理策略进行析构对象。
再看下弱指针的实现,弱指针比较复杂一些:
可以看到2点:
m_ptr 保存对象指针,m_refs负责计数,看下createWeak的实现:
再看下析构:
再看下promote:
通过attemptIncStrong尝试修改强引用计数:
到了这儿关于弱指针的内容也介绍完了。
最后画一个图总结下轻量级指针,强指针,弱指针的关系:
如果是说C++的话,对象指针是指向对象空间首地址的指针,对象引用是对象名的别名。比如:#include<stdio.h>
class foo {}
void func1(foo* f){printf("%p\n",f)} //对象的指针
void func2(foo&f){printf("%p\n",&f)} //对象的引用
int main() {
foo a
printf("%p\n",&a)
func1(&a)
func2(a)
return 0
}
输出的结果应该是三个相同的地址。也应该可以这样认为:通过引用传递对象是隐式地传递了对象的指针。
如果是C#和JAVA的话,对象引用是堆空间中对象实体的句柄。
class foo {}
foo p//此时p=null
p = new foo()//此时在堆里建立了foo的实例的空间,令p引用该实例
欢迎分享,转载请注明来源:夏雨云
评论列表(0条)