cocos2dx源码之 引用计数及自动释放

首先让我们从C/C++的内存管理开始说起。

C语言的创建释放内存使用的是 malloc 和free
c++ 中是 new 和delete
在cocos2dx里面,可以使用c和c++的,也可以使用封装过的 retain和release 间接的去管理内存。


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

void Ref::release()
{
    CCASSERT(_referenceCount > 0, "reference count should be greater than 0");
    --_referenceCount; //引用计数--
    //中间去掉了无关代码
    if (_referenceCount == 0) //引用计数为0的时候delete this
    {
#if CC_REF_LEAK_DETECTION //内存泄露
        untrackRef(this);
#endif
        delete this;
    }
}

下面我们去Ref类中看看_referenceCount刚创建的时候默认值是多少
Ref::Ref()
: _referenceCount(1) // 一个ref对象一开始创建的时候引用计数是1
{
#if CC_ENABLE_SCRIPT_BINDING
    static unsigned int uObjectCount = 0;
    _luaID = 0;
    _ID = ++uObjectCount;
    _scriptObject = nullptr;
#endif
    
#if CC_REF_LEAK_DETECTION
    trackRef(this);
#endif
}

接下来我们去看加入自动释放池之后的事情。看引擎是怎么处理自动释放的。

 
  
#define CREATE_FUNC(__TYPE__) \
static __TYPE__* create() \
{ \
    __TYPE__ *pRet = new(std::nothrow) __TYPE__(); \
    if (pRet && pRet->init()) \
    { \
        pRet->autorelease(); \    //创建成功后第一件事就把对象放入自动释放池。以达到自动管理内存,自动释放指针对应的内存的效果。
        return pRet; \
    } \
    else \
    { \
        delete pRet; \
        pRet = NULL; \
        return NULL; \
    } \
}



跟踪进去就是这样的代码
Ref* Ref::autorelease()
{
    PoolManager::getInstance()->getCurrentPool()->addObject(this);
    return this;
}

一眼就看出,加入自动释放池。

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

放进 _managedObjectArray这个集合里了。

之前说了要想释放一个Ref对象,调用Ref::release就行了。

AutoreleasePool要自动释放肯定会调用这个函数,在这个类中搜一下release(),
果然在AutoreleasePool::clear中找到了。

void AutoreleasePool::clear()
{
    std::vector releasings;
    releasings.swap(_managedObjectArray);//交换 _managedObjectArray 和 releasings
    //交换之后_managedObjectArray会置为空集合,也就是说,每个ref类都只会自动释放一次。也就是初始化的引用计数--变成0。
    //也就解释了为什么刚创建的ref对象,如果不被addchild就会被释放的情况。 下次使用的时候会内存出错。
    for (const auto &obj : releasings)
    {
        obj->release();//一个个释放
    }
}

然后找下哪里调用的这个方法,这个有点难找了。这里可以断点找一下调用的地方。

找到了,是Director导演类的的主循环中。

void DisplayLinkDirector::mainLoop()
{
    if (_purgeDirectorInNextLoop)
    {
        _purgeDirectorInNextLoop = false;
        purgeDirector();
    }
    else if (_restartDirectorInNextLoop)
    {
        _restartDirectorInNextLoop = false;
        restartDirector();
    }
    else if (! _invalid)
    {
        drawScene();
     
        // release the objects
        PoolManager::getInstance()->getCurrentPool()->clear();//这里是主循环,每一帧都会执行,也解释了为什么叫自动释放。。。
    }
}


addchild 的时候会调用retain,remove的时候会调用release。以达到,remove后自动释放的效果。

具体的代码,可以自己去断点查看或者自己猜猜。

retain大致位置是在 insertChild ->_children.pushBack

release大致是在 detachChild -> _children.erase()中



你可能感兴趣的:(带你去看cocos2dx源码)