传统C指针的问题
假设定义一个结构体,其中包含一个指针的成员;在分配结构体内存的时候,就要先为这个指针分配可用的内存,释放结构体的时候,如果没有free 掉这个指针,就会出现内存泄漏的问题。
所以设计需要一个智能指针,可以自动释放这一段内存,当没有其他指针指向它的时候,自动释放内存。
智能指针应用场景.png
设计思路
所以需要设计一种智能指针,维护一个引用到它的对象的计数值,当这个计数为0的时候,表示没有其他对象引用它,可以自动将这个对象销毁。
-
智能指针的值应该由对象本身持有,当没有其他指针指向这个对象的时候,就自动释放
-
要重载一些操作符,比如 = 操作符,指向操作符* = ->,让其具有和普通指针一样的用法。
android 在设计的时候把引用计数器定义为一个公共的类,这个类只有一个成员变量,那就是引用计数成员变量,其他提供智能指针引用的对象,都必须从这个公共类中继承下来,这样不同的对象就天然提供了引用计数器给智能指针使用了。
android 代码分析
代码路径:system/core/libutils/include/utils/StrongPointer.h
system/core/libutils/StrongPointer.cpp
- 智能指针模板类
主要构造方法:
inline sp() : m_ptr(0) { }
sp(T* other); // NOLINT(implicit)
sp(const sp<T>& other);
sp(sp<T>&& other);
重载下面关键的操作符
重载 = 操作符
sp& operator = (T* other);
sp& operator = (const sp<T>& other);
sp& operator = (sp<T>&& other);
重载* -> 操作符
inline T& operator* () const { return *m_ptr; }
inline T* operator-> () const { return m_ptr; }
inline explicit operator bool () const { return m_ptr != nullptr; }
重要方法
inline T* get() const { return m_ptr; } //获取指针指
void force_set(T* other); //强制设置值
void clear(); //将引用计数值清0,对象会销毁
关键属性
T* mptr // 对象的指针值
- 引用计数值公共类
system/core/libutils/include/utils/RefBase.h
所有想用智能指针维护生命周期的对象都要继承这个公共类
关键类:
virtual void onFirstRef(); //很重要, 在构造函数之前会被调用
关键属性:
weakref_impl* const mRefs;
智能指针类图.png-
RefBase 类包含一个weakref_impl 这个类的指针,会在构造的时候,实例化weakref_impl对象
-
weakref_impl 维护了引用计数的值
std::atomic<int32_t> mStrong; // 强引用的值
std::atomic<int32_t> mWeak;// 弱引用的值
RefBase* const mBase; // 记录RefBase 的指针
std::atomic<int32_t> mFlags;// 标志管理策略
mstrong 的初始值为:
#define INITIAL_STRONG_VALUE (1<<28)
当智能指针的模板类构造的时候,会调用RefBase 类的incstrong 函数,
RefBase的incstrong 函数会同时增加mStrong 和 mWeak 的值,表示当前的对象有其他对象引用它。
如果是第一次构造,mStrong等于 初始化值,会调用到 onFirstRef
weakpointer
weakpointer 也是指向一个对象,但是弱引用仅仅记录对象的地址,不能通过弱指针来访问该对象,也就是说不能通过弱指针来调用对象的成员函数或者访问对象额度成员变量想访问弱指针指向的对象,首先要将弱指针升级为强指针(通过wp 类所提供的promote()方法),弱指针所指向的对象有可能是在其他地方被销毁的,如果对象已经被销毁,wp 的pomote 将会返回空指针,这样就能避免出现访问地址出错的情况。
总结
-
为了实现自动释放内存,避免内存泄漏,android 实现了自己的智能指针
-
使用智能指针的类必须继承Refbase 类,并且使用sp 和 wp 模板进行实例化
-
sp strong pointer 会在对象构造的时候自动增加 sp 引用计数值,销毁时减少引用计数值,当计数值为0时,自动销毁对象
-
wp weak pointer 不能直接构造对象,只能指向一个对象的地址,如果要引用对象,需要先调用premote 升级为强指针
网友评论