Cocos2d-x 学习笔记(7) 内存管理 Sprite SpriteFrame Texture2D
1. 总结
Sprite和SpriteFrame和Texture2D关系紧密,三个类都继承了Ref类。精灵有成员精灵帧和纹理,精灵帧有成员纹理。精灵帧和纹理被精灵帧引用时,引用计数增加,不再被引用时,引用计数减少。纹理被精灵帧引用时也同理。
一个纹理可以被多个精灵帧、精灵引用,一个精灵帧可以被多个精灵引用。
为什么纹理缓存容器不用CC的包装类Map
纹理缓存和精灵帧缓存不同,纹理缓存的容器不是包装类,即向容器中增加和删除纹理不会改变纹理的引用计数。
纹理除异步之外不执行autorelease(),精灵和精灵帧在create()执行autorelease()。
纹理不使用autorelease(),确保了不被引用的纹理不会在每帧结束后被自动release(),而是在需要释放的时候调用remove等方法手动执行release(),确保对内存中的纹理手动释放。也是让暂时没用但以后要用的纹理留在内存中,避免以后重新新建该texture。
纹理缓存的addImage方法中,将新纹理加入到容器时,不会增加引用计数。因为在精灵的create方法中,addImage方法执行后执行setTexture方法,使得引用计数加1。
2. Sprite
Sprite成员变量包括:
Texture2D* _texture; /// Texture2D object that is used to render the sprite SpriteFrame* _spriteFrame;
create(...)
我们执行Sprite类的createxxx(...)等方法,都会新建Sprite对象,对成员变量_texture和_spriteFrame等设置默认值,再调用autorelease()方法,将Sprite对象交给内存管理池自动管理。
setTexture(Texture2D *texture)
在给精灵设置纹理时,若纹理指针为空指针,则执行以下方法尝试从纹理缓存中获取Key为CC_2x2_WHITE_IMAGE_KEY的纹理的指针:
_director->getTextureCache()->getTextureForKey(CC_2x2_WHITE_IMAGE_KEY);
若空白纹理不存在于纹理内存,则新建Image类对象从而新建空白纹理。Image对象继承Ref类,新建时默认引用计数=1,在空白纹理的指针赋给纹理指针后,Image对象执行release()方法,从内存中删除。
此时,若参数纹理指针不等于Sprite本身的纹理指针时,参数纹理retain(),本身纹理release(),参数纹理作为本身纹理指针。
setSpriteFrame(SpriteFrame *spriteFrame)
在给精灵设置精灵帧时,若参数精灵帧指针不等于本身精灵帧指针,对本身精灵帧release(),参数精灵帧retain(),参数精灵帧作为本身精灵帧。
~Sprite()
Sprite对象析构时,会对成员_spriteFrame和_texture执行release()。
addChild(...) removeChild(...) 不再赘述。
3. SpriteFrame SpriteFrameCache
精灵帧缓存的容器_spriteFrames是Map<std::string, SpriteFrame*>类型,添加精灵帧和删除都封装了retain()和release()方法
SpriteFrame::create(const std::string& filename, const Rect& rect)
创建精灵帧时,要将精灵帧执行autorelease()方法,放入内存管理池。
~SpriteFrame()
析构时,对精灵帧成员_texture执行release()
SpriteFrame::setTexture(Texture2D * texture)
对精灵帧的成员_texture设置新的时,原先纹理执行release(),新纹理执行retain()。
SpriteFrame::initWithTexture(Texture2D* texture, ...)
用纹理对精灵帧初始化,纹理执行retain()
SpriteFrameCache::removeSpriteFrames()
SpriteFrameCache::removeSpriteFrameByName(const std::string& name)
SpriteFrameCache::addSpriteFramesWithDictionary(ValueMap& dictionary, Texture2D* texture)
删除是对Map容器执行clear(),会对容器中所有精灵帧执行release(),再清空map。删除特定精灵帧,对容器中精灵帧release()。增加特定精灵帧,对容器中精灵帧retain()。
SpriteFrameCache::destroyInstance()
精灵帧缓存是单例,销毁时执行release()。
4. Texture2D TextureCache
纹理缓存是对纹理的缓存,纹理指针以map形式被保存在容器_textures中,容器类型std::unordered_map<std::string, Texture2D*>。
在用Image对象创建纹理时,新建的Image对象使用完后要调用release()及时从内存中删除。
~TextureCache()
析构时对容器中所有纹理执行release()。
addImage(const std::string &path)
在添加纹理到纹理缓存中,如果纹理不存在于缓存,且又新建该纹理失败,就把刚刚new的texture对象release()。
image = new (std::nothrow) Image();
texture = new (std::nothrow) Texture2D(); if (texture && texture->initWithImage(image)) { // ... } else { // ... CC_SAFE_RELEASE(texture); texture = nullptr; }
CC_SAFE_RELEASE(image);
removeAllTextures()
删除缓存容器中所有纹理,实际上是对这些纹理执行release()。
removeUnusedTextures()
删除没有使用的纹理,实际是对引用计数为1的纹理-1。
removeTexture(Texture2D* texture) removeTextureForKey(...)
it->second->release();
it = _textures.erase(it);