日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【cocos2dx】记录解决csb创建font字体造成的内存泄漏问题

發布時間:2023/12/18 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【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()
void FontAtlas::releaseTextures() {for( auto &item: _atlasTextures){item.second->getPath().c_str());item.second->release();}_atlasTextures.clear(); }

在fontatlas的releaseTextures內打斷點,發現根本沒有調用

  • FontAtlas析構函數
FontAtlas::~FontAtlas() {......releaseTextures();...... }

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被調用兩次的原因

  • 調用的堆棧位置
void TextBMFontReader::setPropsWithFlatBuffers(cocos2d::Node *node, const flatbuffers::Table *textBMFontOptions) {......switch (cmfType){case 0:{if (FileUtils::getInstance()->isFileExist(path)){FontAtlas* newAtlas###### FontAtlasCache::getFontAtlasFNT(path); ######if (newAtlas){fileExist = true;}else{errorContent = "has problem";fileExist = false;}}break;}default:break;}if (fileExist){ ###### labelBMFont->setFntFile(path); ######}...... }

通過斷點的堆棧信息查看,csb在創建字體的兩次調用,在TextBMFontReader的setPropsWithFlatBuffers方法內,被我用######標記了出來

  • 第一處調用
if (FileUtils::getInstance()->isFileExist(path)){FontAtlas* newAtlas ###### FontAtlasCache::getFontAtlasFNT(path); ######if (newAtlas){fileExist = true;}else{errorContent = "has problem";fileExist = false;}}break; }

setPropsWithFlatBuffers方法內的第一處調用,這里應該是想通過看能不能創建atlas來判斷.fnt文件是否有問題,但是只要是調用getFontAtlasFNT默認就已經放到cache文件的_atlasMap里了,引用計數為1

  • 第二處調用
if (fileExist) { ###### labelBMFont->setFntFile(path); ###### }void TextBMFont::setFntFile(const std::string& fileName) {......_labelBMFontRenderer->setBMFontFilePath(fileName);...... }bool Label::setBMFontFilePath(const std::string& bmfontFilePath, const Vec2& imageOffset, float fontSize) {FontAtlas *newAtlas = FontAtlasCache::getFontAtlasFNT(bmfontFilePath,imageOffset);if (!newAtlas){reset();return false;}......return true; }

第二處調用,如果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
https://github.com/KingSun5

結語

雖然問題解決了,但是不太清楚是不是當時寫框架的人有別的考量的地方,如果有同學知道有博主沒有考慮到的地方,歡迎留言交流,最后希望看到最后的同學有所收獲,若是覺得博主的文章寫的不錯,不妨關注一下博主,點贊一下博文,另博主能力有限,若文中有出現什么錯誤的地方,歡迎各位評論指摘。
QQ交流群:806091680(Chinar)
該群為CSDN博主Chinar所創,推薦一下!我也在群里!
本文屬于原創文章,轉載請著名作者出處并置頂!!

總結

以上是生活随笔為你收集整理的【cocos2dx】记录解决csb创建font字体造成的内存泄漏问题的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。