安卓智能指针sp、wp、RefBase浅析
目录
- 前言
- 一、RefBase
- 1.1 引用计数机制
- 1.2 设计目的
- 1.3 主要方法
- 1.4 如何使用
- 1.5 小结
- 二、sp和wp
- 2.1 引用计数机制
- 2.2 设计目的
- 2.3 主要方法
- 2.3.1 sp
- 2.3.2 wp
- 2.4 如何使用
- 2.5 小结
- 四、参考链接
前言
安卓底层binder中,为什么 IInterface要继承自RefBase ?常常看到的sp又是什么东西?想要搞懂安卓底层binder,又或是安卓NDK开发,你必须了解这些内容。
一、RefBase
RefBase 是 Android 系统中用于实现引用计数的基类,主要用于管理对象的生存周期。其设计是为了确保在多线程和多组件的环境中正确处理对象的引用计数,从而提高内存管理的安全性和效率。
1.1 引用计数机制
当一个对象被创建时,它的引用计数初始为 1。每当一个新的引用指向该对象时,引用计数加一;每当引用失效时,引用计数减一。当引用计数减到 0 时,对象的析构函数会被调用,内存将被释放。这样可以有效避免内存泄漏并确保在不需要时释放资源。
1.2 设计目的
在多线程环境中,使用引用计数可以使得对象的管理更加安全。当多个线程或组件引用同一个对象时,引用计数机制可以确保对象在引用未被完全释放之前不被销毁,避免了潜在的使用已释放对象的危害。
1.3 主要方法
RefBase 提供了一些基础方法来支持引用计数,例如:
- incStrong() 和 decStrong():
这两个方法分别用于增加和减少对象的强引用计数。强引用保证了对象在有强引用存在时不会被销毁。
- incWeak() 和 decWeak():
这些方法用于弱引用计数管理。弱引用允许对象在没有强引用时被销毁,因此不会阻止对象的析构。
- getStrongCount() 和 getWeakCount():
返回当前的强引用和弱引用计数。
1.4 如何使用
在 Android 中,通常会通过 sp< T>
和 wp< T>
类来使用 RefBase 的引用计数功能。
sp< T>
是一个智能指针,表示强引用,持有对象的强引用;
而 wp< T>
表示弱引用,持有对象的弱引用。
示例代码:
#include <utils/RefBase.h>
class MyObject : public RefBase {
public:
MyObject() { }
~MyObject() { }
void doSomething() {
// 业务逻辑
}
};
int main() {
sp<MyObject> obj = new MyObject(); // 引用计数为 1
{
sp<MyObject> obj2 = obj; // 引用计数增加到 2
obj2->doSomething(); // 可以通过 obj2 调用方法
} // obj2 生命周期结束,引用计数减少到 1
// 继续使用 obj,不会被提前销毁
obj->doSomething();
// 当 obj 超出作用域后,引用计数减少到 0,对象会被销毁
return 0;
}
1.5 小结
RefBase 是 Android 中用于引用计数的基础类。
提供了强引用和弱引用的管理机制,确保在多线程环境中安全地管理对象的生命周期。
使用 sp 和 wp 管理对象时,可以方便地实现内存安全和避免内存泄漏的风险。
二、sp和wp
强指针sp(Strong Pointer)和弱指针wp(Weak Pointer)
2.1 引用计数机制
sp 是一个智能指针,它使用引用计数机制来管理资源。当一个 sp 指针被复制时,它会增加对象的引用计数;当 sp 指针被销毁时,它会减少引用计数。
wp同理,只不过是区分为强引用计数和弱引用计数。
当引用计数变为零时(即没有任何 sp 指针指向该对象),对象会自动被销毁,释放所占的内存。
2.2 设计目的
- 内存管理:通过引用计数机制,sp 和 wp 旨在简化对象的内存管理,避免内存泄露和不必要的内存占用。
- 防止循环引用:使用 sp 和 wp,可以避免由于相互引用导致的循环引用,从而使对象无法释放。
2.3 主要方法
2.3.1 sp
- 提供多种形式的构造方式
- 定义多种形式的赋值运算操作
- 重载操作运算符*,可以获取实际对象
- 重载操作运算符->,可以获取指向实际对象的指针
- 可通过get函数,获取实际对象的指针
- force_set函数可以指定sp引用的实际对象,该函数设计有点缺点,若sp当前已经引用其他的对象,则可能造成其他对象无法释放。
2.3.2 wp
- 提供多种形式的构造方式
- 定义多种形式的赋值运算操作
- 可通过unsafe_get函数,获取实际对象的指针,但是可能获取到的是空的或是野指针
- 可以通过promote函数将弱引用变为强引用,这个是一个比较重要的函数。
2.4 如何使用
一个简单的小demo
#include <utils/RefBase.h>
#include <iostream>
class MyClass : public android::RefBase {
public:
MyClass(int value) : mValue(value) {
std::cout << "MyClass created with value: " << mValue << std::endl;
}
~MyClass() {
std::cout << "MyClass destroyed with value: " << mValue << std::endl;
}
void displayValue() {
std::cout << "Value: " << mValue << std::endl;
}
private:
int mValue;
};
void demonstrateSpAndWp() {
// 创建一个 sp 指向 MyClass 的实例
android::sp<MyClass> strongPtr = new MyClass(42);
strongPtr->displayValue(); // 使用 sp 指针调用方法
// 创建一个 wp 指向 sp 指针的对象
android::wp<MyClass> weakPtr = strongPtr;
// 尝试通过 wp 转换为 sp
if (android::sp<MyClass> tempPtr = weakPtr.promote()) {
tempPtr->displayValue(); // 使用转换后的 sp 指针调用方法
} else {
std::cout << "The object is already destroyed!" << std::endl;
}
// 删除 strongPtr,强引用计数减一
strongPtr = nullptr; // 这会导致 MyClass 对象被销毁
std::cout << "strongPtr set to nullptr." << std::endl;
// 再次检查 wp 指针
if (android::sp<MyClass> tempPtr = weakPtr.promote()) {
tempPtr->displayValue(); // 尝试访问已经被销毁的对象
} else {
std::cout << "The object is already destroyed!" << std::endl;
}
}
int main() {
demonstrateSpAndWp();
return 0;
}
创建一个 sp 指针 strongPtr,指向 MyClass 的实例。调用对象的方法来展示功能。
创建一个 wp 指针 weakPtr,指向 strongPtr。此时对象的引用计数依然有效。
使用 promote() 方法将 wp 转换为一个 sp 指针,以检查对象是否仍然有效并使用它。
将 strongPtr 置为空以释放对象,这将导致 MyClass 的析构函数被调用。
再次检查 weakPtr 指向的对象,证明对象已经被销毁,此时 promote() 将返回空指针,输出相关信息。
2.5 小结
- sp 和 wp 是 Android 提供的智能指针类,使用引用计数机制来实现内存管理。
- sp 主要用于对对象的强引用,自动管理对象的生命周期;
- wp 用于对对象的弱引用,允许检测被引用对象的有效性,同时不会影响其生命周期。
- 正确使用 sp 和 wp 可以有效地减少内存泄漏、提高内存管理的安全性,并防止循环引用问题。
四、参考链接
说了半天,为什么要用引用计数功能?sp、wp、RefBase的源码深度解析?
请看链接文章内容
Android智能指针RefBase、sp、wp解析