Android 自己的智能指针
在 Android 系统中,强指针模板类(sp<T>
) 是一种基于引用计数的智能指针实现,专门用于管理对象的生命周期。它被广泛用于 Android Framework 的底层(Native 层/C++ 代码),尤其是与 Binder 通信相关的模块。
1. sp<T>
的定义与作用
- 模板类:
sp<T>
是一个模板类(定义在<utils/StrongPointer.h>
中),通过泛型支持任意类型的对象。 - 强引用语义:通过引用计数(Reference Counting)跟踪对象的使用情况,确保对象在不再被任何指针引用时自动释放内存。
- 设计目标:解决 Android 系统中 Native 层对象生命周期管理的复杂性,避免内存泄漏和野指针问题。
2. 强指针服务对象
引用计数机制
- 每个被
sp<T>
管理的对象必须继承自RefBase
类(定义在<utils/RefBase.h>
)。 RefBase
提供了两个引用计数器:- 强引用计数(Strong Count):由
sp<T>
管理,归零时对象被销毁。 - 弱引用计数(Weak Count):由
wp<T>
(弱指针)管理,归零时对象的控制块被释放(但对象内存可能已被强引用释放)。
- 强引用计数(Strong Count):由
sp<T>
的实现原理
-
构造
sp<T>
当sp<T>
指向一个对象时,会调用RefBase::incStrong()
增加强引用计数。template<typename T> sp<T>::sp(T* other) : m_ptr(other) {if (other) other->incStrong(this); }
-
析构
sp<T>
当sp<T>
超出作用域或被重置时,调用RefBase::decStrong()
减少强引用计数。若计数归零,销毁对象。template<typename T> sp<T>::~sp() {if (m_ptr) m_ptr->decStrong(this); }
-
赋值与拷贝
拷贝或赋值操作会调整引用计数,确保新旧指针的正确管理:sp<ProcessState> p1 = new ProcessState(); 或者 sp<ProcessState> p1(new ProcessState()); // 强引用计数=1 sp<ProcessState> p2 = p1; // 强引用计数=2
3. sp<T>
与 RefBase
的关系
-
对象必须继承
RefBase
只有继承自RefBase
的类才能被sp<T>
管理。例如:class ProcessState : public virtual RefBase {// ... };
-
RefBase
的关键方法incStrong()
:增加强引用计数。decStrong()
:减少强引用计数,可能触发对象销毁。onFirstRef()
:当强引用计数从 0 变为 1 时调用(首次被引用)。onLastStrongRef()
:当强引用计数归零时调用(即将销毁)。
4. 使用场景示例
示例 1:Binder 代理对象的生命周期管理
在 Binder 通信中,客户端通过 sp<IBinder>
持有服务端的代理对象:
// 获取 ServiceManager 的代理
sp<IServiceManager> sm = defaultServiceManager();// 获取 BatteryService 的 Binder 代理对象
sp<IBinder> binder = sm->getService(String16("battery"));// 将 IBinder 转换为具体的服务接口
sp<IBatteryService> batteryService = interface_cast<IBatteryService>(binder);
sp<T>
确保代理对象在不再被使用时自动释放。
示例 2:单例模式的资源管理
在 ProcessState
单例中,使用 sp<T>
确保全局唯一实例的正确释放:
sp<ProcessState> ProcessState::self() {static sp<ProcessState> gProcess(new ProcessState);return gProcess;
}
5. sp<T>
vs C++ 标准智能指针
特性 | sp<T> (Android) | std::shared_ptr<T> (C++11) |
---|---|---|
依赖对象基类 | 必须继承 RefBase | 无要求(通过 std::enable_shared_from_this 可选) |
性能优化 | 为嵌入式系统优化,轻量级 | 通用实现,可能略重 |
线程安全 | 引用计数操作是原子的(线程安全) | 默认线程安全(依赖实现) |
弱指针支持 | 通过 wp<T> 实现 | 通过 std::weak_ptr<T> 实现 |
内存开销 | 每个对象附带 RefBase 的控制块 | 每个 shared_ptr 有单独的控制块 |
6. 注意事项
-
循环引用
sp<T>
无法自动处理循环引用(如对象 A 持有sp<B>
,对象 B 持有sp<A>
),需结合wp<T>
(弱指针)打破循环。 -
继承
RefBase
若类未继承RefBase
,使用sp<T>
会导致编译错误。 -
跨模块传递
确保对象的所有权通过sp<T>
明确传递,避免裸指针(T*
)脱离智能指针管理。 -
线程安全
虽然sp<T>
的引用计数操作是原子的,但对象本身的线程安全性需开发者自行保证。