1.1.02_COCOS2D-X内存管理之HelloWorld

字数 375阅读 74
  • 启动APP:创建运行HelloWorld场景
bool AppDelegate::applicationDidFinishLaunching()
{
    ...
    // create a scene. it's an autorelease object
    auto scene = HelloWorld::scene();

    // run
    director->runWithScene(scene);

    return true;
}
  • 创建HelloWorld场景对象,并将其加入内存自动回收池。
Scene* HelloWorld::scene()
{
     return HelloWorld::create();
}
Scene* Scene::create()
{
    Scene *ret = new (std::nothrow) Scene();
    if (ret && ret->init())
    {
        ret->autorelease();
        return ret;
    }
    else
    {
       ...
    }
}
  • 创建 new (std::nothrow) Scene(); 时调用根类构造函数,默认_referenceCount引用计数为1
Ref::Ref()
: _referenceCount(1) // when the Ref is created, the reference count of it is 1
...
  • 初始化 * ret->init()* 场景对象后,调用autorelease()函数* ret->autorelease();*,将其加入内存自动回收池。
Ref* Ref::autorelease()
{
    PoolManager::getInstance()->getCurrentPool()->addObject(this);
    return this;
}

此时,HelloWorld场景对象已经被加入了内存自动回收池,并且引用计数为1


  • 运行HelloWorld场景director->runWithScene(scene);
void Director::runWithScene(Scene *scene)
{
    ...
    pushScene(scene);
    ...
}
  • 将其压入场景栈 * _scenesStack.pushBack(scene)*。
void Director::pushScene(Scene *scene)
{
    ...
    _scenesStack.pushBack(scene);
    ...
}
  • 压入栈操作:将对象添加到vector,同时引用计数+1
/** Adds a new element at the end of the Vector. */
void pushBack(T object)
{
    CCASSERT(object != nullptr, "The object should not be nullptr");
    _data.push_back( object );
    object->retain();
}
void Ref::retain()
{
    CCASSERT(_referenceCount > 0, "reference count should be greater than 0");
    ++_referenceCount;
}
  • 到这步,实际上HelloWorld场景对象的引用计数已经为2了(初始化为1,director->runWithScene(scene);操作+1)。

  • 主循环mainLoop每帧都会调用PoolManager::getInstance()->getCurrentPool()->clear();方法,清理析构_managedObjectArray未被引用对象(referenceCount==1),同时将_managedObjectArray清空。
void Director::mainLoop()
{
    ...
    else if (! _invalid)
    {
        drawScene();
        // release the objects
        PoolManager::getInstance()->getCurrentPool()->clear();
    }
}
void AutoreleasePool::clear()
{
    ...
    std::vector<Ref*> releasings;
    releasings.swap(_managedObjectArray);
    for (const auto &obj : releasings)
    {
        obj->release();
    }
    ...
}
void Ref::release()
{
    CCASSERT(_referenceCount > 0, "reference count should be greater than 0");
    --_referenceCount;
    if (_referenceCount == 0)
    {
        ...
        delete this;
    }
}

至此,在下一帧结束前,HelloWorld的场景对象引用计数变成了1。同时由于_managedObjectArray被清空,所以在下下帧时,执行clear就不会再对HelloWorld场景对象做release()处理。也就是说其引用计数保持为1。


  • 外记:
    当下一次调用 *replaceScene(Scene scene) 方法时,释放HelloWorld场景对象,即其引用计数变为0。
void Director::replaceScene(Scene *scene)
{
    ...
    _scenesStack.replace(index, scene);
    ...
}
void replace(ssize_t index, T object)
{
    CCASSERT(index >= 0 && index < size(), "Invalid index!");
    CCASSERT(object != nullptr, "The object should not be nullptr");
    
    _data[index]->release();
    _data[index] = object;
    object->retain();
}

替换当前索引的场景对象,并将原持有对象释放。

推荐阅读更多精彩内容