cocos2dx内存管理解析

今天第一天开始写博客,我想我也会一直的坚持坚持下去,和所有人进行分享和交流,这也是源于对技术的热爱和对游戏的炽热,我想我的这一生都将会奉献给游戏,他是我一辈子的事业更是我这辈子的朋友,好了废话就不多说了,第一篇博客我们就来聊聊cocos2dx的内存管理。
我们首先来看下下面的代码片段

class Ref
{
public:
    void retain();
    void release();
    Ref* autorelease();
 protected:
    unsigned int _referenceCount;
};

而看cocos2dx里面所有的显示对象的基类Node也都公有的继承了Ref(在cocos2dx3.0以下是CCObiect),于是所有的显示对象也都有具有这三个方法,而在看看这三个方法的实现
void Ref::retain()
{
    CCASSERT(_referenceCount > 0, "reference count should greater than 0");
    ++_referenceCount;
}

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 autoreleasepool.");
      }
      delete this;
  }
}
Ref* Ref::autorelease()
{
  PoolManager::getInstance()->getCurrentPool()->addObject(this);
  return this;
}

了解object-c的人通过上面的代码应该都能够明白cocos2dx-c的内存管理其实是和object-c的一模一样的,都是采用引用计数的方法来管理自己的内存的,当创建一个对象的时候他的引用计数器_referenceCount会加一,不要问我为什么,因为_referenceCount在构造函数被初始化了1,在看下面创建一个显示对象的代码

Layer *Layer::create()
{
    Layer *ret = new (std::nothrow) Layer();
    if (ret && ret->init())
    {
        ret->autorelease();
        return ret;
    }
    else
    {
        CC_SAFE_DELETE(ret);
        return nullptr;
    }
}

这是创建一个层的代码new Layer 这个对象的内存快,init初始化这个类里面的逻辑函数或者变量,然后autorelease然后返回,为什么要autorelease呢,看看autorelease这个函数的实现

    Ref* Ref::autorelease()
    {
      PoolManager::getInstance()->getCurrentPool()->addObject(this);
      return this;
    }

原来是把这个对象也就是这个内存快添加到一个全局的PoolManager里面,而为什么要添加到PoolManager这里面呢,看看PoolManager就一目了然

AutoreleasePool* PoolManager::getCurrentPool() const
{
    return _releasePoolStack.back();
}

是获取得到一个 PoolManager 里面AutoreleasePool对象,并且把显示对象添加到AutoreleasePool对象里面的集合对象中(此处我也不太明白作者的用意,单利对象本来就只有一个实例,为毛_releasePoolStack还是一个集合,每次都要拿集合最后的一个AutoreleasePool,而框架由始至终都只往_releasePoolStack集合中添加了一AutoreleasePool对象);这样只要经过autorelease的函数就会添加到PoolManager里面来,而为什么要这样做呢,当然肯定是为了更好的管理内存,而在什么地方管理呢,我们知道cocos2d他只有一个主线程,在那呢,我们找找

void DisplayLinkDirector::mainLoop()
{
    if (_purgeDirectorInNextLoop)
    {
        _purgeDirectorInNextLoop = false;
        purgeDirector();
    }
    else if (! _invalid)
    {
        drawScene();

        // release the objects
        PoolManager::getInstance()->getCurrentPool()->clear();
    }
}

我们看到了PoolManager::getInstance()->getCurrentPool()->clear();这一句,其他的我们以后章节在来讲他们的愿意,本章节我们只看框架的内存管理模块,我们继续看PoolManager里面的clear方法

void AutoreleasePool::clear()
{
    for (const auto &obj : _managedObjectArray)
    {
        obj->release();
    }
    _managedObjectArray.clear();
}

他会调用所有添加到AutoreleasePool对象的release方法,看来release非常重要,我们继续研究release方法

    if (_referenceCount == 0)
    {
        auto poolManager = PoolManager::getInstance();
        if (!poolManager->getCurrentPool()->isClearing() && poolManager->isObjectInPools(this))
        {
            delete this;
        }
    }

这下应该能够一目了然了,当显示对象的引用计数器为0的时候他就会自动的删除自己,所以这样就能够很巧妙的管理创建或者说是new出来的对象了,而当什么时候引用计数器会加1什么时候会减1呢我们继续深入的研究

void Node::insertChild(Node* child, int z)
{
    _transformUpdated = true;
    _reorderChildDirty = true;
    _children.pushBack(child);
    child->_localZOrder = z;
}

当一个对象往另外一个对象上添加时,都会调用addChild方法,而addChild必调用insertChild方法,而insertChild方法其中的 _children.pushBack(child)这一句

  void pushBack(T object)
    {
        CCASSERT(object != nullptr, "The object should not be nullptr");
        _data.push_back( object );
        object->retain();
    }

他会调用retain方法,retain会将引用计数器加1现在_referenceCount = 2,而当移除显示对象时必须会调用removeChild,则他同时也会调用release()函数,此时_referenceCount会–_referenceCount会变成1,当程序执行下一帧的时候,他继续会–_referenceCount;然后当_referenceCount = 0的时候就会删除此对象
这样就构成了一个先是对象从产生到销毁的整个过程,所以当我们使用的时候就一定要注意了,手动retain的使用完毕后,必须要手动调用release(),否则他永远不会删除这段内存,从而造成内存泄漏。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值