13.【cocos2d-x 源码分析】:内存管理的详细分析

对应源码位置:(1)cocos2d-x-3.3\cocos\base\CCRef ;(2)cocos2d-x-3.3\cocos\base\CCAutoreleasePool
内存管理的在引擎中的位置
void DisplayLinkDirector::mainLoop()
{
    if (_purgeDirectorInNextLoop)
    {
        _purgeDirectorInNextLoop = false;
        purgeDirector();
    }
    else if (! _invalid)
    {
        drawScene();
     
        // release the objects
        //清空 当前内存池的
        PoolManager::getInstance()->getCurrentPool()->clear();
    }
}
这要从Ref说起

凡是需要进行自动内存管理的对象都要继承自Ref类。

class CC_DLL Ref
{
public:
    void retain();
    void release();
    Ref* autorelease();
    unsigned int getReferenceCount() const;
protected:
    Ref();
public:
	//析构函数 为 虚函数 从而可以保证正确的析构函数可以被调用
    virtual ~Ref();
protected:
    //传说中的 引用计数
    unsigned int _referenceCount;
    friend class AutoreleasePool;
};

其实现也很简单。

//初始的时候 为1
Ref::Ref()
: _referenceCount(1) // when the Ref is created, the reference count of it is 1
{
}

Ref::~Ref()
{
}

void Ref::retain()
{
	//计数 加1
    CCASSERT(_referenceCount > 0, "reference count should greater than 0");
    ++_referenceCount;
}

void Ref::release()
{
    CCASSERT(_referenceCount > 0, "reference count should greater than 0");
    --_referenceCount;
	//如果为 0 就删除自身
    if (_referenceCount == 0)
    {
        delete this;
    }
}

Ref* Ref::autorelease()
{
	//将其加入 自动内存管理
    PoolManager::getInstance()->getCurrentPool()->addObject(this);
    return this;
}
//获取 当前 引用计数
unsigned int Ref::getReferenceCount() const
{
    return _referenceCount;
}
AutoreleasePool的实现

其主要思想为 以Node为例,当生成一个Node对象时,它的引用计数为1,然后她会主动加入到AutoreleasePool中,。
一种情况是:当他被加入到父节点,此时父节点将他的计数加1。在这一帧最后,AutoreleasePool进行清理,将该对象计数减1,此时计数为1。AutoreleasePool清理后将管理的队列清空,因为他只管这一帧的,此后他也是安然无恙,当父节点移除他之后,它的计数为0,因此调用析构函数清理。
另一种情况,没有父节点收留他,一直计数为1,到这一帧最后AutoreleasePool进行清理,将该对象计数减1,此时计数为0,因此调用析构函数清理,合理。

class CC_DLL AutoreleasePool
{
public:
    AutoreleasePool();
    //给个名字
    AutoreleasePool(const std::string &name);
    ~AutoreleasePool();
	//添加 管理对象
    void addObject(Ref *object);
	//清理
    void clear();
    //检查是否包含 某个对象
    bool contains(Ref* object) const;
private:
	//很简单 就是一个vector
    std::vector<Ref*> _managedObjectArray;
    //名字
    std::string _name;
};
//其具体实现
AutoreleasePool::AutoreleasePool()
: _name("")
{
    _managedObjectArray.reserve(150);
    PoolManager::getInstance()->push(this);
}

AutoreleasePool::AutoreleasePool(const std::string &name)
: _name(name)
{
	//预分配 150个 空间
    _managedObjectArray.reserve(150);
    //将自身加入到PoolManager
    PoolManager::getInstance()->push(this);
}

AutoreleasePool::~AutoreleasePool()
{
    //清理 后 将自身出栈
    clear();
    PoolManager::getInstance()->pop();
}

void AutoreleasePool::addObject(Ref* object)
{
    _managedObjectArray.push_back(object);
}

void AutoreleasePool::clear()
{
	//对每一个 管理的 对象  执行其release
    for (const auto &obj : _managedObjectArray)
    {
        obj->release();
    }
    //最重要的是 清空了 vector 只是对这一帧的对象进行管理
    _managedObjectArray.clear();
}
//看是否 包含
bool AutoreleasePool::contains(Ref* object) const
{
	//逐个遍历  看是否包含 这个对象
    for (const auto& obj : _managedObjectArray)
    {
        if (obj == object)
            return true;
    }
    return false;
}
PoolManager的实现

AutoreleasePool本身是为了在每一帧的末尾使用,也就是说需要清理的对象(即为管理的引用计数为1对象)在这一帧的末尾清理,但是还存在有些帧生成了大量需要清理的对象,因此需要在某些情况下,实现用户自定义的AutoreleasePool来缩短清理周期。这就是 PoolManager起的作用。

{
	//此时  其构造函数 已经将自身加入到 PoolManager中
	//也就是 目前所有的 管理工作由这个新生成的接管
	new AutoreleasePool();
	auto p1=new Node();
	p1->autorelease();
	auto p2=new Node();
	p2->autorelease();
	auto p3=new Node();
	p3->autorelease();
	//出了这个 花括号 
	//周期过了 进行清理  将自身出栈
	//来达到 小于一个帧的目的
}

看看 PoolManager

class CC_DLL PoolManager
{
public:
    static PoolManager* getInstance();
    static void destroyInstance();
    AutoreleasePool *getCurrentPool() const;
    bool isObjectInPools(Ref* obj) const;
    friend class AutoreleasePool;
private:
    PoolManager();
    ~PoolManager(); 
    void push(AutoreleasePool *pool);
    void pop();
    static PoolManager* s_singleInstance;
  	//也是很简单  只是用来装 AutoreleasePool
    std::vector<AutoreleasePool*> _releasePoolStack;
};
//实现
PoolManager* PoolManager::s_singleInstance = nullptr;

PoolManager* PoolManager::getInstance()
{
    if (s_singleInstance == nullptr)
    {
        s_singleInstance = new (std::nothrow) PoolManager();
        // Add the first auto release pool
        //这是第一个 它的构造函数 就会找到这个PoolManager并加入。
        new AutoreleasePool("cocos2d autorelease pool");
    }
    return s_singleInstance;
}

void PoolManager::destroyInstance()
{
    delete s_singleInstance;
    s_singleInstance = nullptr;
}

PoolManager::PoolManager()
{
    _releasePoolStack.reserve(10);
}

PoolManager::~PoolManager()
{
   //挨个删除
    while (!_releasePoolStack.empty())
    {
        AutoreleasePool* pool = _releasePoolStack.back();
        delete pool;
    }
}

AutoreleasePool* PoolManager::getCurrentPool() const
{
	//返回栈顶pool
    return _releasePoolStack.back();
}

bool PoolManager::isObjectInPools(Ref* obj) const
{
	//逐个 遍历 其管理的 池子 看是否包含本对象
    for (const auto& pool : _releasePoolStack)
    {
        if (pool->contains(obj))
            return true;
    }
    return false;
}

void PoolManager::push(AutoreleasePool *pool)
{
	//入栈
    _releasePoolStack.push_back(pool);
}

void PoolManager::pop()
{
	//出栈
    _releasePoolStack.pop_back();
}
RefPtr的实现

他是仿照share_ptr实现的。对于单个元素,如要内存自动管理,则要手动进行releaseretain,很不方便。因此将其进行一层封装,将其包装到局部变量的析构/构造函数中,方便计数管理。

//对于 do{}while(0);方式的宏使用方式 可参考 https://www.jianshu.com/p/99efda8dfec9
#define CC_REF_PTR_SAFE_RETAIN(ptr)\
    \
    do\
    {\
        if (ptr)\
        {\
            const_cast<Ref*>(static_cast<const Ref*>(ptr))->retain();\
        }\
    \
    }   while (0);

#define CC_REF_PTR_SAFE_RELEASE(ptr)\
    \
    do\
    {\
        if (ptr)\
        {\
            const_cast<Ref*>(static_cast<const Ref*>(ptr))->release();\
        }\
    \
    }   while (0);

#define CC_REF_PTR_SAFE_RELEASE_NULL(ptr)\
    \
    do\
    {\
        if (ptr)\
        {\
            const_cast<Ref*>(static_cast<const Ref*>(ptr))->release();\
            ptr = nullptr;\
        }\
    \
    }   while (0);
//具体实现
template <typename T> class RefPtr
{
public:
    
    inline RefPtr()
    :
        _ptr(nullptr)
    {
        
    }
    //移动构造函数
    inline RefPtr(RefPtr<T> && other)
    {
        _ptr = other._ptr;
        other._ptr = nullptr;
    }

    inline RefPtr(T * ptr)
    :
        _ptr(const_cast<typename std::remove_const<T>::type*>(ptr))     // Const cast allows RefPtr<T> to reference objects marked const too.
    {
        CC_REF_PTR_SAFE_RETAIN(_ptr);
    }
    
    inline RefPtr(std::nullptr_t ptr)
    :
        _ptr(nullptr)
    {
        
    }
    
    inline RefPtr(const RefPtr<T> & other)
    :
        _ptr(other._ptr)
    {
        CC_REF_PTR_SAFE_RETAIN(_ptr);
    }
    
    inline ~RefPtr()
    {
        CC_REF_PTR_SAFE_RELEASE_NULL(_ptr);
    }
    
    inline RefPtr<T> & operator = (const RefPtr<T> & other)
    {
        if (other._ptr != _ptr)
        {
            CC_REF_PTR_SAFE_RETAIN(other._ptr);
            CC_REF_PTR_SAFE_RELEASE(_ptr);
            _ptr = other._ptr;
        }
        
        return *this;
    }
    
    inline RefPtr<T> & operator = (RefPtr<T> && other)
    {
        if (&other != this)
        {
            CC_REF_PTR_SAFE_RELEASE(_ptr);
            _ptr = other._ptr;
            other._ptr = nullptr;
        }
        
        return *this;
    }
    
    inline RefPtr<T> & operator = (T * other)
    {
        if (other != _ptr)
        {
            CC_REF_PTR_SAFE_RETAIN(other);
            CC_REF_PTR_SAFE_RELEASE(_ptr);
            _ptr = const_cast<typename std::remove_const<T>::type*>(other);     // Const cast allows RefPtr<T> to reference objects marked const too.
        }
        
        return *this;
    }
    
    inline RefPtr<T> & operator = (std::nullptr_t other)
    {
        CC_REF_PTR_SAFE_RELEASE_NULL(_ptr);
        return *this;
    }
    
    // Note: using reinterpret_cast<> instead of static_cast<> here because it doesn't require type info.
    // Since we verify the correct type cast at compile time on construction/assign we don't need to know the type info
    // here. Not needing the type info here enables us to use these operations in inline functions in header files when
    // the type pointed to by this class is only forward referenced.
    
    inline operator T * () const { return reinterpret_cast<T*>(_ptr); }
    
    inline T & operator * () const
    {
        CCASSERT(_ptr, "Attempt to dereference a null pointer!");
        return reinterpret_cast<T&>(*_ptr);
    }
    
    inline T * operator->() const
    {
     	//使用 reinterpret_cast 不需要类型信息
        return reinterpret_cast<T*>(_ptr);
    }
    
    inline T * get() const { return reinterpret_cast<T*>(_ptr); }
    
    
    inline bool operator == (const RefPtr<T> & other) const { return _ptr == other._ptr; }
    
    inline bool operator == (const T * other) const { return _ptr == other; }
    
    inline bool operator == (typename std::remove_const<T>::type * other) const { return _ptr == other; }
    
    inline bool operator == (const std::nullptr_t other) const { return _ptr == other; }
    
    
    inline bool operator != (const RefPtr<T> & other) const { return _ptr != other._ptr; }
    
    inline bool operator != (const T * other) const { return _ptr != other; }
    
    inline bool operator != (typename std::remove_const<T>::type * other) const { return _ptr != other; }
    
    inline bool operator != (const std::nullptr_t other) const { return _ptr != other; }
    
    
    inline bool operator > (const RefPtr<T> & other) const { return _ptr > other._ptr; }
    
    inline bool operator > (const T * other) const { return _ptr > other; }
    
    inline bool operator > (typename std::remove_const<T>::type * other) const { return _ptr > other; }
    
    inline bool operator > (const std::nullptr_t other) const { return _ptr > other; }
    
    
    inline bool operator < (const RefPtr<T> & other) const { return _ptr < other._ptr; }
    
    inline bool operator < (const T * other) const { return _ptr < other; }
    
    inline bool operator < (typename std::remove_const<T>::type * other) const { return _ptr < other; }
    
    inline bool operator < (const std::nullptr_t other) const { return _ptr < other; }
    
        
    inline bool operator >= (const RefPtr<T> & other) const { return _ptr >= other._ptr; }
    
    inline bool operator >= (const T * other) const { return _ptr >= other; }
    
    inline bool operator >= (typename std::remove_const<T>::type * other) const { return _ptr >= other; }
    
    inline bool operator >= (const std::nullptr_t other) const { return _ptr >= other; }
    
        
    inline bool operator <= (const RefPtr<T> & other) const { return _ptr <= other._ptr; }
    
    inline bool operator <= (const T * other) const { return _ptr <= other; }
    
    inline bool operator <= (typename std::remove_const<T>::type * other) const { return _ptr <= other; }
    
    inline bool operator <= (const std::nullptr_t other) const { return _ptr <= other; }
    
        
    inline operator bool() const { return _ptr != nullptr; }
        
    inline void reset()
    {
        CC_REF_PTR_SAFE_RELEASE_NULL(_ptr);
    }
        
    inline void swap(RefPtr<T> & other)
    {
        if (&other != this)
        {
            Ref * tmp = _ptr;
            _ptr = other._ptr;
            other._ptr = tmp;
        }
    }
    //弱引用 不增加计数
    inline void weakAssign(const RefPtr<T> & other)
    {
        CC_REF_PTR_SAFE_RELEASE(_ptr);
        _ptr = other._ptr;
    }
    
private:
    Ref * _ptr;
};
最后

下一篇 分析 音频系统 的实现。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值