cocos2d x 3.3rc2 004 cocos中的引用计数和自动释放池 ReleasePoolTest - cheyiliu/All-in-One GitHub Wiki

源码分析

  • 代码+注释, 重点从计数器角度看本质

// 定义个具有引用计数功能的类,即继承Ref class TestObject : public Ref { public: TestObject() : _name(""){}

TestObject(std::string name) : _name(name)
{
    CCLOG("TestObject:%s is created", _name.c_str());
}

~TestObject()
{
    if (_name.size() > 0)
        CCLOG("TestObject:%s is destroyed", _name.c_str());
}

private: std::string _name; };

void ReleasePoolTestScene::runThisTest() { //xxx 无关代码略

TestObject *obj = new (std::nothrow) TestObject("testobj");//构造,计数器=1
obj->autorelease();//放入autoreleasepool
assert(obj->getReferenceCount() == 1);//pass

// should retain first before invoking autorelease
obj->retain();//计数器=2
obj->autorelease();//放入autoreleasepool
assert(obj->getReferenceCount() == 2);//pass

// create an autorelease pool in stack
{
    AutoreleasePool pool1;//在栈上构建了一个autoreleasepool,

// 同时更新了PoolManager的栈,当前pool变为pool1

    // can invoke autorelease more than once
    obj->retain();//计数器=3
    obj->autorelease();//放入pool1
    assert(obj->getReferenceCount() == 3);//pass
    obj->retain();//计数器=4
    obj->autorelease();//放入pool1
    assert(obj->getReferenceCount() == 4);//pass
    
    // retain, release can work together with autorelease pool
    obj->retain();//计数器=5
    assert(obj->getReferenceCount() == 5);//pass
    obj->release();//计数器=4
    assert(obj->getReferenceCount() == 4);//pass
}//块作用域结束,pool1这个栈变量的生命周期结束,调用析构函数,

//清理pool(由于通过2次调用autorelease,使得变量obj被2次加入pool1, //故在clear时obj被调用2次release, 计时器变为4-2=2); 同时更新PoolManager的栈。 //从另外一个角度看,只要这个块作用域中用法正确(retain和release或autorelease配对), //则可直接忽略块中的代码调用次数,并得出结论assert(obj->getReferenceCount() == 2); //是pass的。 类似于进栈保存现场,出栈恢复现场。 //这里页解答了上一节中的疑问,为何PoolManager有个栈结构。

assert(obj->getReferenceCount() == 2);//pass

// example of using temple autorelease pool
{
    AutoreleasePool pool2;////在栈上构建了一个autoreleasepool,同时更新了PoolManager的栈,当前pool变为pool2
    char name[20];
    for (int i = 0; i < 100; ++i)
    {
        snprintf(name, 20, "object%d", i);
        TestObject *tmpObj = new (std::nothrow) TestObject(name);// 每一个tmpObj的计数器=1
        tmpObj->autorelease();//加入pool2
    }
}//块作用域结束,pool2这个栈变量的生命周期结束,调用析构函数,

//清理pool2(并调用每个tmpobj的release 1次,计数器变为0, 释放内存); 同时更新PoolManager的栈。 //从另外一个角度看,只要这个块作用域中用法正确(retain和release或autorelease配对), //则可直接忽略块中的代码调用次数,和代码块对作用域外的影响。 //类似于进栈保存现场,出栈恢复现场。 //这里页解答了上一节中的疑问,为何PoolManager有个栈结构。

// object in pool2 should be released

{
    //new AutoreleasePool;//我将这两句代码放到cpp-empty-test中来跑,有异常
    //PoolManager::destroyInstance();//但为何在test-cpps中可以跑起来?? 望高手指点。

//以下是我修改的测试代码 auto x = new AutoreleasePool;//在堆上创建pool delete x;//手动释放 //貌似这里也解答了上一节中的疑问。 //将AutoreleasePool放在栈空间,可以充分利用局部变量的生命周期的特性,不需要手动释放。 //若将AutoreleasePool放在堆上,则需要手动释放 }

// xxx

}

⚠️ **GitHub.com Fallback** ⚠️