【cocos2dx】记录解决csb创建font字体造成的内存泄漏问题
目錄
- 前言
- 找bug過程
- 重寫CCTexure2D的retain和release
- FontAtlas查找紋理釋放
- 查找FontAtlas的釋放
- 查找FontAtlas的創建
- 查找getFontAtlasFNT被調用兩次的原因
- 問題總結
- 解決思路
- 手動釋放一次atlas
- 少調用一次
- 推送
- 結語
前言
最近做資源的重新加載和釋放的時候發現了一個問題,在切換場景的時候去釋放所有資源,在轉場成功后發現有部分字體的紋理沒有被釋放,進一步調查,發現沒有被釋放的問題都是csb內創建的font字體,所以本篇文章記錄了查找內存泄漏的過程和解決方案
找bug過程
重寫CCTexure2D的retain和release
-
retain
-
TextureCache::AddImage
-
TextureAtlas::initWithTexture
-
FontAtlas::addTexture
-
在retain通過斷點查看堆棧,可以看到font的png在創建后一共經過三次retain
通過csb創建的字體和手動create的字體沒有區別,都是這三次
-
release
-
create代碼創建
-
TextureAtlas::~TextureAtlas()
-
FontAtlas::releaseTextures()
-
-
csb創建
- TextureAtlas::~TextureAtlas()
-
在release內斷點的堆棧可以看出csb創建的font字體少了一個FontAtlas內釋放Texture的過程
FontAtlas查找紋理釋放
- releaseTextures()
在fontatlas的releaseTextures內打斷點,發現根本沒有調用
- FontAtlas析構函數
releaseTextures在FontAtlas的析構函數被調用,打斷點發現析構函數沒有被調用,也就是說FontAtlas沒有被釋,這里初步懷疑FontAtlas在創建的時候被多引用了
查找FontAtlas的釋放
Label::~Label() {......if (_fontAtlas){......FontAtlasCache::releaseFontAtlas(_fontAtlas);}...... }通過堆棧信息找到,FontAtlas的釋放是在Label的析構函數內,在這里打斷點,發現果然,_fontAtlas通過csb創建的時候引用計數是2,通過create手動創建引用計數是1
查找FontAtlas的創建
FontAtlas* FontAtlasCache::getFontAtlasFNT(const std::string& fontFileName, const Vec2& imageOffset /* = Vec2::ZERO */) {......auto it = _atlasMap.find(atlasName);if ( it == _atlasMap.end() ){auto font = FontFNT::create(realFontFilename, imageOffset);if(font){auto tempAtlas = font->createFontAtlas();if (tempAtlas){_atlasMap[atlasName] = tempAtlas;return _atlasMap[atlasName];}}}else{_atlasMap[atlasName]->retain();return _atlasMap[atlasName];}return nullptr; }FontAtlas通過FontAtlasCache的getFontAtlasFNT來獲取和創建
如果FontAtlas從沒有創建過,那么就create一個新的放到_atlasMap里緩存,默認創建后引用計數1
如果FontAtlas創建過,從_atlasMap里取出來,引用計數加1
在這里打斷點,發現create創建的font字體只調用了getFontAtlasFNT了一次,csb創建的font字體調用了兩次
查找getFontAtlasFNT被調用兩次的原因
- 調用的堆棧位置
通過斷點的堆棧信息查看,csb在創建字體的兩次調用,在TextBMFontReader的setPropsWithFlatBuffers方法內,被我用######標記了出來
- 第一處調用
setPropsWithFlatBuffers方法內的第一處調用,這里應該是想通過看能不能創建atlas來判斷.fnt文件是否有問題,但是只要是調用getFontAtlasFNT默認就已經放到cache文件的_atlasMap里了,引用計數為1
- 第二處調用
第二處調用,如果atlas能創建成功,就調用了Label的setBMFontFilePath方法,很不幸,在setBMFontFilePath方法內又調用了一遍getFontAtlasFNT,這就造成一個字體在創建的時候引用了兩次
問題總結
通過上述的過程,發現問題出現在通過csb創建font字體的時候,相關的數據文件在創建后被多引用了一次,造成切場景是,label不能把atlas釋放掉,結果atlas下關聯的字體texture的引用計數也不會被減少
解決思路
手動釋放一次atlas
void TextBMFontReader::setPropsWithFlatBuffers(cocos2d::Node *node, const flatbuffers::Table *textBMFontOptions){......FontAtlas* newAtlas = nullptr;switch (cmfType){case 0:{if (FileUtils::getInstance()->isFileExist(path)){newAtlas = FontAtlasCache::getFontAtlasFNT(path);if (newAtlas){fileExist = true;}else{errorContent = "has problem";fileExist = false;}}break;}default:break;}if (fileExist){labelBMFont->setFntFile(path);FontAtlasCache::releaseFontAtlas(newAtlas);}......}第一種修改方式,在labelBMFont->setFntFile(path);后手動釋放一下新創建的tlas
少調用一次
void TextBMFontReader::setPropsWithFlatBuffers(cocos2d::Node *node, const flatbuffers::Table *textBMFontOptions){......switch (cmfType){case 0:{if (FileUtils::getInstance()->isFileExist(path)){labelBMFont->setFntFile(path);}break;}default:break;}......}直接舍棄掉atlas的創建判斷過程,在用的時候直接創建
推送
- Github
結語
雖然問題解決了,但是不太清楚是不是當時寫框架的人有別的考量的地方,如果有同學知道有博主沒有考慮到的地方,歡迎留言交流,最后希望看到最后的同學有所收獲,若是覺得博主的文章寫的不錯,不妨關注一下博主,點贊一下博文,另博主能力有限,若文中有出現什么錯誤的地方,歡迎各位評論指摘。
QQ交流群:806091680(Chinar)
該群為CSDN博主Chinar所創,推薦一下!我也在群里!
本文屬于原創文章,轉載請著名作者出處并置頂!!
總結
以上是生活随笔為你收集整理的【cocos2dx】记录解决csb创建font字体造成的内存泄漏问题的全部內容,希望文章能夠幫你解決所遇到的問題。