Cocos2d-X与游戏开发

cocos2d-x源码中的内存管理

2018-08-03  本文已影响3人  二号猎人

cocos2d-x的内存管理原则——引用计数机制

内存管理:引用计数机制, 当一个对象执行retain操作的时候,引用计数加1,当执行release操作的时候,引用计数减1,当引用计数为0时,此对象被释放。

通过基类Ref的代码实现,便可以明白基本的内存管理机制,直接打开 CCRef.cpp文件

//  我们直接来看看CCRef.cpp文件
Ref::Ref()
: _referenceCount(1)  //注:当Ref对象被创建,此对象的引用计数为1

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

void Ref::release()   //release方法
{
    CCASSERT(_referenceCount > 0, "reference count should be greater than 0");
    --_referenceCount;  //引用计数减1

    if (_referenceCount == 0) //当引用计数为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; //删除对象!!!
    }
}

Ref* Ref::autorelease()  //autorelease方法
{
    PoolManager::getInstance()->getCurrentPool()->addObject(this);   //将对象加入到自动释放池中
    return this;
}

unsigned int Ref::getReferenceCount() const
{
    return _referenceCount;  //获取引用计数个数
}

通过看Ref类的源码,可以得出结论:

1.当一个对象被创建的时候,将此对象的引用计数设置为1
2.当执行一次retain,引用计数加1,
3.执行一次release,引用计数减1
4.当引用计数为0的时候,此对象被释放delete

Ref的autorelease方法

Ref* Ref::autorelease()  //autorelease方法
{
    PoolManager::getInstance()->getCurrentPool()->addObject(this);   //将对象加入到自动释放池中
    return this;
}

什么时候调用autorelease方法?

    Label* Label::create()
    {
        auto ret = new (std::nothrow) Label;
    
        if (ret)
        {
            ret->autorelease();  //create函数里,会自动执行autorelease方法
        }
    
        return ret;
    }

可以看出,在create函数里,会自动执行autorelease方法, 也就是加入到自动释放池

AutoreleasePool 自动释放池:

它有个属性_managedObjectArray,可以将执行了autorelease方法的Ref对象加入_managedObjectArray,当AutoreleasePool::clear()时,也就是对_managedObjectArray中的每一项执行release操作

PoolManager 自动释放池管理类

有个生成器属性_releasePoolStack,里面加入的都是AutoreleasePool的对象,可以获取当前的AutoreleasePool

可以看到实现是建立了一个PoolManager的单例,接下来看看PoolManager,有个生成器属性_releasePoolStack

PoolManager* PoolManager::s_singleInstance = nullptr;

PoolManager* PoolManager::getInstance()
{  //PoolManager是个单例
    if (s_singleInstance == nullptr)
    {
        s_singleInstance = new (std::nothrow) PoolManager();
        // Add the first auto release pool
        new AutoreleasePool("cocos2d autorelease pool");
    }
    return s_singleInstance;
}
AutoreleasePool* PoolManager::getCurrentPool() const
{
    return _releasePoolStack.back(); //_releasePoolStack最后的一个AutoreleasePool对象
}

//注意接下来的两个函数:push,pop
void PoolManager::push(AutoreleasePool *pool)
{
    _releasePoolStack.push_back(pool); //在_releasePoolStack这个vector尾部加入pool
}

void PoolManager::pop()
{
    CC_ASSERT(!_releasePoolStack.empty());
    _releasePoolStack.pop_back();//删除_releasePoolStack最后一个元素
}

PoolManager::getInstance()->getCurrentPool()->addObject(this)中的getCurrentPool可以看出获取到了一个AutoreleasePool对象,然后我们查看AutoreleasePool

class CC_DLL AutoreleasePool
{   
private:
    std::vector<Ref*> _managedObjectArray;   //AutoreleasePool有个生成器属性_managedObjectArray,用来装Ref对象
};

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

void AutoreleasePool::clear() //清楚操作
{
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
    _isClearing = true;
#endif
    std::vector<Ref*> releasings;
    releasings.swap(_managedObjectArray);  //遍历_managedObjectArray,为每一个对象执行release操作
    for (const auto &obj : releasings)
    {
        obj->release();
    }
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
    _isClearing = false;
#endif
}

PoolManager::getInstance()->getCurrentPool()->addObject(this)中的addObject其实就是给_managedObjectArray这个vector中添加一个Ref对象

可以看到AutoreleasePool::clear()的方法实现,其实是把_managedObjectArray里面的每一个对象执行一次release操作,clear函数会在DisplayLinkDirector的mainLoop函数中被调用,一帧调用一次,及时回收。

void DisplayLinkDirector::mainLoop()
{
    if (_purgeDirectorInNextLoop)
    {
        _purgeDirectorInNextLoop = false;
        purgeDirector();
    }
    else if (_restartDirectorInNextLoop)
    {
        _restartDirectorInNextLoop = false;
        restartDirector();
    }
    else if (! _invalid)
    {
        drawScene();
     
        // release the objects !!!在此处执行clear操作
        PoolManager::getInstance()->getCurrentPool()->clear();
    }
}

总结一下就是内存管理的源代码实现:

常见的label,button等对象在执行create()函数的时候,会自动执行autorelease()方法,就是将对象添加到AutoreleasePool的_managedObjectArray中,而在游戏中每一帧都会调用通过PoolManager获取到当前的AutoreleasePool对象,然后执行AutoreleasePool::clear()方法,给_managedObjectArray中的每一个对象执行release操作。

上一篇下一篇

猜你喜欢

热点阅读