前言
在整理一个功能的时候,发现做了一个对象池用来缓存ScrollView的子节点,这里面手动的去retain和release对象池内的Node,碰到了一些小问题记录一下
问题整理
- 问题1:
Node创建后不添加,引用计数即为1
- 问题2:
创建Node后手动retain,引用计数为2,一帧后引用计数变为了1
- 问题3:
引用计数为1的Node,先release再添加到场景上出问题,Node不存在
引用、释放、自动释放
之前也就大概的看了一下引用和释放的逻辑,有些细节没看到,趁机再看了一下造成问题的原因
retain
: _referenceCount(1) // when the Ref is created, the reference count of it is 1
void Ref::retain()
{
CCASSERT(_referenceCount > 0, "reference count should be greater than 0");
++_referenceCount;
}
在Ref内最基础的方法,引用,很简单这里,Ref在创建的时候,引用计数默认为1,retain被调用的话,引用计数会加一
release
void Ref::release()
{
CCASSERT(_referenceCount > 0, "reference count should be greater than 0");
--_referenceCount;
if (_referenceCount == 0)
{
......
delete this;
}
}
release被调用的时候,引用计数会减一,在引用计数为0后,会释放掉当前节点,所以问题3中不能先释放
autorelease
Ref* Ref::autorelease()
{
PoolManager::getInstance()->getCurrentPool()->addObject(this);
return this;
}
Node * Node::create()
{
Node * ret = new (std::nothrow) Node();
if (ret && ret->init())
{
ret->autorelease();
}
else
{
CC_SAFE_DELETE(ret);
}
return ret;
}
本次的重点是这个autorelease,之前一直没注意,Node在创建后会被默认设置为一个自动释放,自动释放干了什么呢,如下所示
void AutoreleasePool::addObject(Ref* object)
{
_managedObjectArray.push_back(object);
}
设置为autorelease后,当前节点会被添加到AutoreleasePool的_managedObjectArray数组内
void AutoreleasePool::clear()
{
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
_isClearing = true;
#endif
std::vector<Ref*> releasings;
releasings.swap(_managedObjectArray);
for (const auto &obj : releasings)
{
obj->release();
}
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
_isClearing = false;
#endif
}
在对象池的clear的方法里,会吧_managedObjectArray数组内的节点都release一遍,再清空数组
void Director::mainLoop()
{
if (_purgeDirectorInNextLoop)
{
_purgeDirectorInNextLoop = false;
purgeDirector();
}
else if (_restartDirectorInNextLoop)
{
_restartDirectorInNextLoop = false;
restartDirector();
}
else if (! _invalid)
{
drawScene();
// release the objects
PoolManager::getInstance()->getCurrentPool()->clear();
}
}
在主循环内没帧都会调用对象池的clear方法,所以其实当前节点创建后,下一帧引用计数就会自动-1,如果没有用到这个节点,在下一帧就会被释放掉了
总结
综上所述,我们已经可以很清楚的看明白cocos引用计数的原理
Ref在被创建的时候,默认引用计数+1
继承自Ref的Node在初始化的时候,会默认设置成autorelease
被设置成autorelease状态的节点,如果引用计数<=1,也就是创建后不添加为子节点,也不手动retain,那么下一帧就会被自动释放掉
想要常驻内存不被释放,可以选择添加为别的节点的子节点,在addChild的时候,引用计数会+1,或者手动retain调用一下
推送
- Github
https://github.com/KingSun5
结语
若是觉得博主的文章写的不错,不妨关注一下博主,点赞一下博文,另博主能力有限,若文中有出现什么错误的地方,欢迎各位评论指摘。
QQ交流群:806091680(Chinar)
该群为CSDN博主Chinar所创,推荐一下!我也在群里!
本文属于原创文章,转载请著名作者出处并置顶!!