目录

  • 前言
  • 找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字体造成的内存泄漏问题相关推荐

  1. 讲述Sagit.Framework解决:双向引用导致的IOS内存泄漏(上)

    前言: 好久没写文章了,最近先是重构IT恋.又重写IT恋中. Sagit框架也不断的更新,调整,现在感觉已完美了了相当的多. 今天不写教程,先简单分享一下技术内容. 1:见Block必有:#defin ...

  2. 一次完整的JVM堆外内存泄漏故障排查记录

    前言 记录一次线上JVM堆外内存泄漏问题的排查过程与思路,其中夹带一些JVM内存分配机制以及常用的JVM问题排查指令和工具分享,希望对大家有所帮助. 在整个排查过程中,我也走了不少弯路,但是在文章中我 ...

  3. Android之内存泄漏以及解决办法(持更)

    Android之内存泄漏以及解决办法 文章链接:http://blog.csdn.net/qq_16628781/article/details/67761590 知识点: 单例造成的内存泄漏原因和解 ...

  4. 内存泄漏的检测、定位和解决经验总结

    内存泄漏的检测.定位和解决经验总结 温辉敏(wenhm@sina.com) 2006 年 05 月 [摘要] 结合局端MCU项目中CSS.NMS模块内存泄漏检测.修正的过程,简要介绍了内存泄漏检测的工 ...

  5. 5 个 Android 开发中比较常见的内存泄漏问题及解决办法

    Android开发中,内存泄漏是比较常见的问题,有过一些Android编程经历的童鞋应该都遇到过,但为什么会出现内存泄漏呢?内存泄漏又有什么影响呢? 在Android程序开发中,当一个对象已经不需要再 ...

  6. Android 系统(87)---常见的内存泄漏原因及解决方法

    常见的内存泄漏原因及解决方法 (Memory Leak,内存泄漏) 为什么会产生内存泄漏? 当一个对象已经不需要再使用本该被回收时,另外一个正在使用的对象持有它的引用从而导致它不能被回收,这导致本该被 ...

  7. Android应用内存泄漏的定位、分析与解决策略

    Hello,大家好,我是Clock.翻了一下简书,发现有一个多月没有更新博客,本来今天打算和妹纸去电影院看<你的名字>,然后再去到处浪的. 结果因为妹纸公司临时有事,她不得不回公司一趟.. ...

  8. 什么是javascript内存泄漏?以及解决方法

    什么是javascript内存泄漏?以及解决方法 一.什么是javascript内存泄漏? 二.常见的内存泄漏 1.意外的全局变量(通常是变量未被定义或者胡乱引用了全局变量) 2.计时器 3.闭包 4 ...

  9. 什么是内存泄漏,常见引起引起内存泄漏的原因,及解决办法

    一:什么是内存泄露 内存泄露是指:内存泄漏也称作"存储渗漏",用动态存储分配函数动态开辟的空间,在使用完毕后未释放,结果导致一直占据该内存单元.直到程序结束.(其实说白了就是该内存 ...

  10. 快速定位解决Android内存泄漏

    此文章来源于APP架构师这个公众号 今天的主题是Android开发中的内存泄漏,之所以说这个是因为前几天做了项目中的内存泄漏排查与解决,在这里总结一下,被提供一种快速定位解决Android内存泄漏的方 ...

最新文章

  1. 爬虫之常见的反爬手段和解决思路
  2. 用户画像从0到100的构建思路
  3. ECSTORE 关于FILTER条件所代表的含义
  4. oracle压缩参数,Oracle 11g版本EXPDP 的COMPRESSION参数压缩比堪比“gzip -9”
  5. 转(HP大中华区总裁孙振耀退休感言)
  6. 带着canvas去流浪系列之一:绘制柱状图
  7. Ubuntu报错:E: The repository http://ppa.launchpad.net/fcitx-team does not have a Release file.
  8. SQL数据同步到ELK(四)- 利用SQL SERVER Track Data相关功能同步数据(上)
  9. mysql 删除用户下的所有表_使用PL/SQL快速删除用户下的所有表数据
  10. mysql大数据量的分页查询优化
  11. Python爬虫学习(八)----scrapy框架
  12. 模拟按钮控件BN_CLICKED消息事件
  13. Android性能优化篇——友盟U-APM云真机
  14. 【离散数学】陪集的详解
  15. php正则中英文数字,PHP正则匹配中英文、数字及下划线方法
  16. java计算机毕业设计ssm+vue心理咨询网站
  17. Linux发行版制作总结
  18. 抽奖逻辑java_Java 利用binarySearch实现抽奖计算逻辑
  19. Strange Printer
  20. 社区发现(一):社区简介

热门文章

  1. 软工网络15团队作业4——Alpha阶段敏捷冲刺之Scrum 冲刺博客(Day3)
  2. NeHe OpenGL教程 第十三课:图像字体
  3. 学而思王帆初中语文教学视频
  4. Java中的条件运算符
  5. 页面设计如何进行颜色搭配
  6. ClickHouse S3 外表调研
  7. python取字符串首字母_python字符串操作
  8. Django前后端分离概念解析
  9. 祝贺光环2014年6月28日PMP考试通过率90.28%
  10. (已解决)报错:collect2 error ld returned 1 exit status