从零开始のcocos2dx生活(一)内存管理

cocos中所有的对象都是继承自Ref基类,Ref的职责就是对对象进行引用计数管理

内存管理中最重要的是三个方法retain()、release()、autorelease()

在cocos中创建对象的标准流程是:
创建对象->初始化->添加到自动内存管理->返回创建成功的对象
就比如下面这段代码1:创建Node对象

//代码1
Node * Node::create()
{
    Node * ret = new (std::nothrow) Node();
    if (ret && ret->init())
    {
        ret->autorelease();
    }
    else
    {
        CC_SAFE_DELETE(ret);
    }
    return ret;
}

在代码1中,我们只需要调用create方法就可以实现创建对象、初始化和自动管理内存。

在cocos中有的函数中直接使用了create的宏定义,调用对象的create方法就可以执行代码2,实现的功能和代码1是一样的。

//代码2
#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 = nullptr; \
        return nullptr; \
    } \
}

代码2中调用autorelease方法,将对象加入自动内存管理池自动管理。
代码3是autorelease方法的实现

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

首先看一下代码4,PoolManager的getInstance方法
在代码4中创建了PoolManager对象并调用了this的AutoreleasePool方法(代码5)
"cocos2d autorelease pool"是这个自动管理池的name

//代码4
PoolManager* PoolManager::getInstance()
{
    if (s_singleInstance == nullptr)
    {
        s_singleInstance = new (std::nothrow) PoolManager();
        // Add the first auto release pool
        new AutoreleasePool("cocos2d autorelease pool");
    }
    return s_singleInstance;
}

在代码5中可以看到先是对_managedObjectArray预留空间,然后将this加了进去

//代码5
AutoreleasePool::AutoreleasePool(const std::string &name)
: _name(name)
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
, _isClearing(false)
#endif
{
    _managedObjectArray.reserve(150);
    PoolManager::getInstance()->push(this);
}

在代码3中还调用了getCurrentPool方法用来获取当前的内存管理池

//代码6
AutoreleasePool* PoolManager::getCurrentPool() const
{
    return _releasePoolStack.back();
}

然后把this加入到当前的内存管理池中作为一个ref对象进行管理,如代码7

//代码7
void AutoreleasePool::addObject(Ref* object)
{
    _managedObjectArray.push_back(object);
}

整个流程如下图所示
管理流程

自动内存管理的结构如下图,用一个栈来存储多个自动内存管理池,在自动内存管理池中又有若干个ref对象。
内存管理结构

在内存管理中主要是靠引用计数来记录对象的使用情况,当一个对象被create时会给它分配内存,并且会调用retain()方法让引用计数+1;当调用release()时会让引用计数-1,release时会检查引用计数是否为0,引用计数为0时会调用delete删除对象并释放内存。

在每一帧结束时会清理当前的内存管理池,将每一个ref对象的引用计数都-1,这帧结束之后,内存管理池中就没有这个ref对象了,引用计数是ref自己的属性,当下一次被release时如果引用计数=0,就会被释放。

void Director::mainLoop()
{
	......
    PoolManager::getInstance()->getCurrentPool()->clear();
    }
}
void AutoreleasePool::clear()
{
    std::vector<Ref*> releasings;
    releasings.swap(_managedObjectArray);
    for (const auto &obj : releasings)
    {
        obj->release();
    }
}

retain()和release()只是帮助我们记录一个对象的引用次数,在程序中几乎不用手动调用。

原文地址:https://www.cnblogs.com/sakuraneo/p/11992054.html