COCOS2DX引擎深入二————内存管理


我会先用几句话概括,然后在慢慢深入。

先考虑个问题。

为什么要引进内存管理?

c++不像java,c#有自己的垃圾回收机制。所以很容易出现用完的内存空间没有被回收,即内存泄露。所以要引进内存管理。

cocos2dx用到的内存管理技术是引用技术。即当对象增加一次引用时,计数器加一;减少一时,计数器减一。分别对应引用计数类Ref的retain()和rrelease();


 

class CC_DLL Ref
{
public:
    /**
     * 增加一次引用计数
     */
    void retain();
     
    /**
     * 释放一次计数,具体里面怎么释放的,下面我们跟定义的代码做分析
     */
    void release();
 
    /**
     * 自动释放
     */
    Ref* autorelease();
 
    /**
     * 得到当前对象的引用计数的值,也是是被引用了多少次
     */
    unsigned int getReferenceCount() const;
     
protected:
    /**
     * Constructor
     *
     * The Ref's reference count is 1 after construction.
     * @js NA
     */
    Ref();
     
public:
    /**
     * @js NA
     * @lua NA
     */
    virtual ~Ref();
     
protected:
    /// 用来记录引用次数的变量值
    unsigned int _referenceCount;
     
    friend class AutoreleasePool;
     
#if CC_ENABLE_SCRIPT_BINDING
public:
    /// 对象的ID
    unsigned int        _ID;
    /// 这个变量这里猜测是lua脚本中引用的ID
    int                 _luaID;
#endif
};

凡是继承了Ref的类都是自动释放类,这些类每次创建完之后,引用都为1。看到Ref有个autorelease()和一个友元类AutoreleasePool,这是内存管理用到的一个很重要的类。

那他们是干嘛的呢?

我们知道类创建完后,如果没被用到或不用了,内存是需要被回收的,否则就会出现内存泄露的情况。cocos2dx每一帧结束都会进行内存回收。

怎么回收呢?

先把调用了autorelease的对象加入到AutoreleasePool这个回收池里面,每一帧结束后将AutoreleasePool里的所有对象进行一次release(),并清空。

Ref* Ref::autorelease()
{
    PoolManager::getInstance()->getCurrentPool()->addObject(this);
    return this;
}
void DisplayLinkDirector::mainLoop()
{
    if (_purgeDirectorInNextLoop)
    {
        _purgeDirectorInNextLoop = false;
        purgeDirector();
    }
    else if (! _invalid)
    {
        drawScene();
     
        // release the objects
        PoolManager::getInstance()->getCurrentPool()->clear();
    }
}

void AutoreleasePool::clear()
{
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
    _isClearing = true;
#endif
    for (const auto &obj : _managedObjectArray)
    {
        obj->release();
    }
    _managedObjectArray.clear();
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
    _isClearing = false;
#endif
}
void Ref::release()
{
    CCASSERT(_referenceCount > 0, "reference count should greater than 0");
    --_referenceCount;
     
    if (_referenceCount == 0)
    {
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
        auto poolManager = PoolManager::getInstance();
        if (!poolManager->getCurrentPool()->isClearing() && poolManager->isObjectInPools(this))
        {
           
            CCASSERT(false, "The reference shouldn't be 0 because it is still in autorelease pool.");
        }
#endif
        delete this;
    }
}

 

对象被创建的时候引用为1,如果在一帧结束前,对象被其他类用到了,然后该对象调用了retain(),引用为2,那么AutoreleasePool释放的时候调用release()后,引用为1,则不会回收;

如果在一帧结束前,一直未调用retain(),那么就将被回收。



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值