Android智能指针
Android和gecko底层都是由c++来实现的,而c++最头痛的就是内存泄漏问题了,常见的c++项目中的指针问题基本上有以下几种:
-
指针没有初始化
-
new了对象后没有及时delete
-
野指针
智能指针需要做什么
智能指针就是用来解决上面的这些问题的。
-
首先智能指针必须解决初始化问题,这个问题比较简单,只要让指针在创建的时候设置值为null即可(比如,把智能指针设计为一个类,通过构造函数来初始化)
-
其次智能指针需要实现new和delete的配套,即new了对象后要及时的delete掉。这个过程必须自动(否则就不叫智能了)。即智能指针必须能判断某一块内存是否需要回收。
假定智能指针为SmartPoint,所指对象为object,那么显然其实现应该如下
template <typename T>
class SmartPoint
{
public:
inline SmartPoint() : m_ptr(0) {} //构造函数初始化
private:
T* m_ptr; //指向object对象
}
但是什么时候释放内存呢,当然是“当不需要的时候”。什么时候是不需要的时候呢?思考一下,我们可以得出:如果有一个指针指向object,那就代表后者是被需要的;而如果一个对象没有指针指向它,那就是不被需要的(已经不需要了)。这种时候这个对象就应该被释放。
考虑到可能有两个以上的指针指向一个对象,只需要有一个计数器来记录该内存对象被需要的个数,如果计数器为0,则说明这个对象已经不被需要了。这个概念就是在很多领域都广泛应用的“引用计数”了。
那么现在来考虑下,计数器应该由谁来管理呢?
- 智能指针
- object自身
如果由智能指针拥有计数器,如果一个对象只有一个指针指向它,那没什么问题,但是如果有多个指针,多个指针之间并不能知道其他指针是否还指向对象,无法判断对象什么时候能释放,故计数器只能由object(对象)自身来管理。
安卓的LightRefBase类
我们为有计数器需求的对象实现一个含有计数器的统一的“父类”,这样只要object继承了该父类,它就具备了计数器的功能。安卓中就实现了一个LightRefBase类
template <class T>
class LightRefBase
{
public:
inline LightRefBase() : mCount(0) { }
inline void incStrong(__attribute__((unused)) const void* id) const {
__sync_fetch_and_add(&mCount, 1);
}
inline void decStrong(__attribute__((unused)) const void* id) const {
if (__sync_fetch_and_sub(&mCount, 1) == 1) {
delete static_cast<const T*>(this);
}
}
//! DEBUGGING ONLY: Get current strong ref count.
inline int32_t getStrongCount() const {
return mCount;
}
typedef LightRefBase<T> basetype;
protected:
inline ~LightRefBase() { }
private:
friend class ReferenceMover;
inline static void moveReferences(void*, void const*, size_t,
const ReferenceConverterBase&) { }
private:
mutable volatile int32_t mCount;
};
LightRefBase类主要有两个方法 incStrong
和decStrong
,分别用来加减计数器;其中decStrong
还需要在计数器为0 的时候释放内存(即不被需要了)。
显然incStrong
会在对象被引用时被调用,故应该重载智能指针的=
等符号,当引用对象时调用incStrong
,同理,智能指针析构时也应该调用decStrong
。具体的例子可以参照android中sp(强指针)的实现。
强指针sp(Strong Point)
以下路径有sp 的源码
./system/core/include/utils/StrongPointer.h
./frameworks/rs/cpp/util/StrongPointer.h
./frameworks/rs/server/StrongPointer.h
先来看看sp的类
template <typename T>
class sp
{
public:
inline sp() : m_ptr(0) { }
sp(T* other);
sp(const sp<T>& other);
template<typename U> sp(U* other);
template<typename U> sp(const sp<U>& other);
~sp();
// Assignment
sp& operator = (T* other);
sp& operator = (const sp<T>& other);
template<typename U> sp& operator = (const sp<U>& other);
template<typename U> sp& operator = (U* other);
//! Special optimization for use by ProcessState (and nobody else).
void force_set(T* other);
// Reset
void clear();
// Accessors
inline T& operator* () const { return *m_ptr; }
inline T* operator-> () const { return m_ptr; }
inline T* get() const { return m_ptr; }
// Operators
COMPARE(==)
COMPARE(!=)
COMPARE(>)
COMPARE(<)
COMPARE(<=)
COMPARE(>=)
private:
template<typename Y> friend class sp;
template<typename Y> friend class wp;
void set_pointer(T* ptr);
T* m_ptr;
};
可以看到其中的接口基本和我们分析的一致,比如其中运算符重载:
template<typename T>
sp<T>& sp<T>::operator = (T* other)
{
if (other) other->incStrong(this);
if (m_ptr) m_ptr->decStrong(this);
m_ptr = other;
return *this;
}
注意这里考虑了对一个智能指针重复赋值的情况,如果m_ptr不为空,要先撤销它之前指向的内存对象,然后才能赋新值。
另,sp分配内存对象不一定是通过运算符,比如构造函数:
template<typename T>
sp<T>::sp(T* other)
: m_ptr(other)
{
if (other) other->incStrong(this);
}
当然因为是构造函数,m_ptr之前必定没有赋过值。
析构函数同理
template<typename T>
sp<T>::~sp()
{
if (m_ptr) m_ptr->decStrong(this);
}
弱指针wp
弱引用是一个对象引用的持有者,使用弱引用后可以维持对对象的引用,但是不会阻止其被垃圾回收。如果一个对象只有弱引用了,那它就成为被垃圾回收的候选对象,就像没有剩余的引用一样,而且一旦对象被删除,所有的弱引用也会被清除
Android6.0源码中RefBase源文件出现的位置
Android6.0中源码位置和Android4.3已经不同
./prebuilts/ndk/9/platforms/android-19/arch-x86/usr/include/rs/cpp/util/RefBase.h
./prebuilts/ndk/9/platforms/android-19/arch-arm/usr/include/rs/cpp/util/RefBase.h
./prebuilts/ndk/9/platforms/android-19/arch-mips/usr/include/rs/cpp/util/RefBase.h
./system/core/include/utils/RefBase.h
./system/core/libutils/RefBase.cpp
./frameworks/rs/cpp/util/RefBase.h
./frameworks/rs/server/RefBase.h