【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字体造成的内存泄漏问题相关推荐
- 讲述Sagit.Framework解决:双向引用导致的IOS内存泄漏(上)
前言: 好久没写文章了,最近先是重构IT恋.又重写IT恋中. Sagit框架也不断的更新,调整,现在感觉已完美了了相当的多. 今天不写教程,先简单分享一下技术内容. 1:见Block必有:#defin ...
- 一次完整的JVM堆外内存泄漏故障排查记录
前言 记录一次线上JVM堆外内存泄漏问题的排查过程与思路,其中夹带一些JVM内存分配机制以及常用的JVM问题排查指令和工具分享,希望对大家有所帮助. 在整个排查过程中,我也走了不少弯路,但是在文章中我 ...
- Android之内存泄漏以及解决办法(持更)
Android之内存泄漏以及解决办法 文章链接:http://blog.csdn.net/qq_16628781/article/details/67761590 知识点: 单例造成的内存泄漏原因和解 ...
- 内存泄漏的检测、定位和解决经验总结
内存泄漏的检测.定位和解决经验总结 温辉敏(wenhm@sina.com) 2006 年 05 月 [摘要] 结合局端MCU项目中CSS.NMS模块内存泄漏检测.修正的过程,简要介绍了内存泄漏检测的工 ...
- 5 个 Android 开发中比较常见的内存泄漏问题及解决办法
Android开发中,内存泄漏是比较常见的问题,有过一些Android编程经历的童鞋应该都遇到过,但为什么会出现内存泄漏呢?内存泄漏又有什么影响呢? 在Android程序开发中,当一个对象已经不需要再 ...
- Android 系统(87)---常见的内存泄漏原因及解决方法
常见的内存泄漏原因及解决方法 (Memory Leak,内存泄漏) 为什么会产生内存泄漏? 当一个对象已经不需要再使用本该被回收时,另外一个正在使用的对象持有它的引用从而导致它不能被回收,这导致本该被 ...
- Android应用内存泄漏的定位、分析与解决策略
Hello,大家好,我是Clock.翻了一下简书,发现有一个多月没有更新博客,本来今天打算和妹纸去电影院看<你的名字>,然后再去到处浪的. 结果因为妹纸公司临时有事,她不得不回公司一趟.. ...
- 什么是javascript内存泄漏?以及解决方法
什么是javascript内存泄漏?以及解决方法 一.什么是javascript内存泄漏? 二.常见的内存泄漏 1.意外的全局变量(通常是变量未被定义或者胡乱引用了全局变量) 2.计时器 3.闭包 4 ...
- 什么是内存泄漏,常见引起引起内存泄漏的原因,及解决办法
一:什么是内存泄露 内存泄露是指:内存泄漏也称作"存储渗漏",用动态存储分配函数动态开辟的空间,在使用完毕后未释放,结果导致一直占据该内存单元.直到程序结束.(其实说白了就是该内存 ...
- 快速定位解决Android内存泄漏
此文章来源于APP架构师这个公众号 今天的主题是Android开发中的内存泄漏,之所以说这个是因为前几天做了项目中的内存泄漏排查与解决,在这里总结一下,被提供一种快速定位解决Android内存泄漏的方 ...
最新文章
- 爬虫之常见的反爬手段和解决思路
- 用户画像从0到100的构建思路
- ECSTORE 关于FILTER条件所代表的含义
- oracle压缩参数,Oracle 11g版本EXPDP 的COMPRESSION参数压缩比堪比“gzip -9”
- 转(HP大中华区总裁孙振耀退休感言)
- 带着canvas去流浪系列之一:绘制柱状图
- Ubuntu报错:E: The repository http://ppa.launchpad.net/fcitx-team does not have a Release file.
- SQL数据同步到ELK(四)- 利用SQL SERVER Track Data相关功能同步数据(上)
- mysql 删除用户下的所有表_使用PL/SQL快速删除用户下的所有表数据
- mysql大数据量的分页查询优化
- Python爬虫学习(八)----scrapy框架
- 模拟按钮控件BN_CLICKED消息事件
- Android性能优化篇——友盟U-APM云真机
- 【离散数学】陪集的详解
- php正则中英文数字,PHP正则匹配中英文、数字及下划线方法
- java计算机毕业设计ssm+vue心理咨询网站
- Linux发行版制作总结
- 抽奖逻辑java_Java 利用binarySearch实现抽奖计算逻辑
- Strange Printer
- 社区发现(一):社区简介