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
}