cocos2dx内存管理解析

前端之家收集整理的这篇文章主要介绍了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(),否则他永远不会删除这段内存,从而造成内存泄漏。

原文链接:https://www.f2er.com/cocos2dx/343692.html

猜你在找的Cocos2d-x相关文章