美文网首页Cocos2d-X与游戏开发
cocos2d-x源码中的内存管理

cocos2d-x源码中的内存管理

作者: 二号猎人 | 来源:发表于2018-08-03 20:38 被阅读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操作。

    相关文章

      网友评论

        本文标题:cocos2d-x源码中的内存管理

        本文链接:https://www.haomeiwen.com/subject/uaiuvftx.html