cocos2dx 内存管理
欢迎转载,转载请注明原文地址: http://www.52php.cn/article/p-oggvgroc-hh.html 本文基于cocos2d-x 3.4 一、cocos2dx内存管理基础cocos2dx内存管理是基于引用计数的。使用了基类Ref实现类对象的引用计数记录。引擎中的所有需要管理的类都派生自Ref。(eg:Node,Sprite,Texture2D…) class CC_DLL Ref
{
public:
void retain();
void release();
Ref* autorelease();
unsigned int getReferenceCount() const;
protected:
Ref();
public:
virtual ~Ref();
protected:
/// count of references
unsigned int _referenceCount;
friend class AutoreleasePool;
};
CCRef.cpp Ref::Ref()
: _referenceCount(1) // when the Ref is created,the reference count of it is 1
{
}
Ref::~Ref()
{
}
void Ref::retain()
{
CCASSERT(_referenceCount > 0,"reference count should be greater than 0");
++_referenceCount;
}
void Ref::release()
{
CCASSERT(_referenceCount > 0,"reference count should be greater than 0");
--_referenceCount;
if (_referenceCount == 0)
{
delete this;
}
}
Ref* Ref::autorelease()
{
PoolManager::getInstance()->getCurrentPool()->addObject(this);
return this;
}
代码很简单,主要就是retain(),release(),autorelease(),_referenceCount和AutoreleasePool。 1.autorelease为什么先看autorelease呢,因为autorelease是cocos2dx内存管理的根基,就是把对象放入到自动释放池(AutoreleasePool)中管理。 2.retainretain的作用就是:令其引用计数增1,表示获取该对象的引用权。我称之为认领,如果对象没有被认领,那么就会释放掉。在什么时候释放? void DisplayLinkDirector::mainLoop()
{
...
else if (! _invalid)
{
drawScene();
// release the objects
PoolManager::getInstance()->getCurrentPool()->clear();
}
}
void AutoreleasePool::clear()
{
for (const auto &obj : _managedObjectArray)
{
obj->release();
}
_managedObjectArray.clear();
}
retain():令其引用计数增1,表示获取该对象的引用权。也就是认领对象,如果对象没有被认领,那么就会 3.release()要真正释放的时候调用,无论是主动调用去释放,还是代码中自动遍历去释放,都需要经过这个函数,令其引用计数值减1,表示释放该对象的引用权。当引用计数为0的时候,就真正释放对象。 4.AutoreleasePool管理自动释放的对象。(当释放池自身被释放的时候,它就会对池中的所有对象执行一次release()方法) 也就是说,如果对象没有被认领(比如addChild,我们稍后讨论),那么在每一帧drawScene之后,调用AutoreleasePool.clear()->Ref.release(),减少引用计数,然后就会释放掉没被认领的对象,如果被认领呢?那就只是把创建的时候的引用计数给减掉,然后由调用者或者引擎其他管理者管理。 AutoreleasePool的vector每次只管理一帧内创建的对象,然后drawScene()之后会clear掉。 那么被认领的对象,什么时候释放呢?我们来看看引擎中怎么用的。 二、引擎用法1.addChildNode里面有一个addChild函数,addChild会调用retain来认领对象,你是不是没有找到,反正我最初怎么也找不到 void Node::insertChild(Node* child,int z)
{
_transformUpdated = true;
_reorderChildDirty = true;
_children.pushBack(child);
child->_localZOrder = z;
}
void pushBack(T object)
{
CCASSERT(object != nullptr,"The object should not be nullptr");
_data.push_back( object );
object->retain();
}
pushBack!!! 那么释放的时候就简单了 removeChild里面有一个_children.erase(childIndex);(当然不只一个接口,还有类似的地方) 2.addImageCCTextureCache里面有一个重载函数 Texture2D* addImage(const std::string &filepath);
Texture2D* addImage(Image *image,const std::string &key);
实现里面有一点不同,下面那个接口使用的时候 _textures.insert( std::make_pair(key,texture) );
texture->retain();
texture->autorelease();
调用了retain和autorelease,而上面的接口并没有调用这两行代码,当时百思不得其解,现在看来,也只是放不放到AutoreleasePool而已,对它的释放来讲,并没有什么区别。因为它的释放是在 void TextureCache::removeAllTextures()
{
for( auto it=_textures.begin(); it!=_textures.end(); ++it ) {
(it->second)->release();
}
_textures.clear();
}
在这个以及相关的函数 eg:removeUnusedTextures,removeTexture… 里面释放的。 三、结论AutoreleasePool有什么用?简单来说,没什么用。但是引擎底层是这么写的,你又必须按着它的写法来,不然很可能报错。 好吧,还是有用的,它的用途就是防止你手动create了一个对象,但是,没有任何地方引用,也没有任何地方释放,这个时候AutoreleasePool就发挥作用了,他会帮你释放。前提是你调用了autorelease(),(create帮我们做了)。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |