纹理内存的问题,急!(在线)

当前项目中遇到这样的问题:
通过 ImageView ,create 一个已加载的纹理缓存(plist)时,会进入
void Sprite::setSpriteFrame(const std::string &spriteFrameName)
{
SpriteFrameCache *cache = SpriteFrameCache::getInstance();
SpriteFrame *spriteFrame = cache->getSpriteFrameByName(spriteFrameName);

CCASSERT(spriteFrame, "Invalid spriteFrameName");


setSpriteFrame(spriteFrame);

}

这里的断言,相信开发人员应该很了解代码结构, cache->getSpriteFrameByName(spriteFrameName); 这个方法里面已经进行过spriteFrame的判断。但是在cache>getSpriteFrameByName(spriteFrameName);内部确没出错。

先说一下现在的内存情况:因为后期大量的纹理加入项目, 我们使用的是 预加载进内存,所以现在纹理内存占用非常大,在上一个版本,和以前的项目中是没有出现这种问题的,但是现在出现了。

一个已经加载成功的纹理,当我去使用它的时候,发现这个纹理是一个空指针。 或者已经加载好的一张plist,当加载显示其中的spriteframe时,也会出现空指针,进入上面断言,或者进入
这段代码
bool Sprite::initWithTexture(Texture2D *texture)
{
CCASSERT(texture != nullptr, “Invalid texture for sprite”);

Rect rect = Rect::ZERO;
rect.size = texture->getContentSize();


return initWithTexture(texture, rect);

}

的断言中,特别是在小内存机型上很容易出现。

所以想问一下 引擎开发者,造成这种情况的原因?
是因为 内存使用达到峰值? 导致部分纹理丢失?或者其他你们 已知的情况。
谢谢,在线等。
(注:无任何纹理路径写入错误,所以不用回是否是纹理路径,或者key书写出错)

好多。

明确几点:

1.我可以理解说是你载入了spriteframe,然后再取某个spriteframe的时候取不到?

2.是在导入大量纹理后出现的?

3.哪个纹理null是随机的,不固定?无法重现?

你明确的几点 是对的。是的,不是固定的,无法重现。 同一个应用, 有可能刚到主场景就进入断言,某个纹理取出后为空,有可能隔一会后 某个纹理又为空,现在我们程序中 都没显示的调用纹理的 release,没有手动清除 纹理。

比如我有一个叫public 的plist,当显示某一个界面的时候,这个public 的plist 里面的某些纹理是能加载显示的,有些就进入断言出错,出错会在
CCASSERT(spriteFrame, “Invalid spriteFrameName”);

或者我载入单张已经加载过的图片,偶尔也会进入断言 使用
Sprite::createWithTexture(TextureCache::getInstance()->getTextureForKey(“xxx/xxx/xxx.jpg”)) 会进入
CCASSERT(texture != nullptr, “Invalid texture for sprite”); 该断言
但是图片加载并没有出错或者异常。

出现该问题,是在最近一个包新加很多资源问题后出现,而且在小内存机器上很容易出现,pad 一般不会出现,p4上特别容易出现。

你们在引擎的 TextureCache 和 SpriteFrameCache 中已经做了 异常捕获,现在的问题是 在这两个cache中,并没有捕捉到异常,而是在外部sprite使用时出现。

1.引擎版本?
2.在Mac会吗?真机(iphone,ipad)?android?低内存会?内存足够不会?

以我这最新的3.3为例。

先说SpriteFrameCache,我看了下源码,getSpriteFrameByName()并不承诺返回非空值(找不到同样返回nullptr),所以在setSpriteFrame()断言是正常的。

而TextureCache,所有纹理是放在一个 std::unordered_map 中。getTextureForKey(xxx)返回了nullptr说明没有在_textures这个map中,这点也应该是没问题的。

所以建议是,如果你没有去手动做释放动作,先抓几个关键点。调用std::string TextureCache::getCachedTextureInfo() const 观察对比一下纹理。。。

确认:1.是不是每次都加载了 2.哪个点丢了纹理? 3.系统级的内存警告log?

我遇到过这种情况,有时候纹理显示不出来,但是游戏运行正常,碰撞都正常,说明精灵还在,但就是不显示,我中途清理、重编、重启IDE,重启电脑折腾了一下,又好了,搞的我莫名其妙。顺便说一下,我用的3.2版本,VS2013

是创建成功,不显示?=。=是exe吧?偶发还是固定?打到安卓上会吗?

是不是收到内存警告的时候释放了没引用的纹理,所以导致这个问题。ios下收到内存警告它会自动释放没引用的纹理

看看,断点 removeUnusedTextures

谢谢 解答, 现在正在解决,8楼说的, 我去测试一下。 大致方向应该是内存达到阈值, 因为在测试中发现通讯用的 data对象会出现new失败返回null。

而且程序并,crash。 还是再运行。 只是手机上打印能看见错误打印。

猜测 frameCache初始化时,new 失败,但是在map表中占了键值引用,所以使用的时候会进入 CCASSERT(spriteFrame, “Invalid spriteFrameName”); 这个断言。

但是很奇怪, 为什么C++ new失败了不会抛错? 网上查了下,现代编译器默认 都用的是 new(nothrow:缺省) 关键字进行对象创建。

是的, 在PC 上测试时不会出现,只有在机器上才会出现,在上一包纹理没爆棚增长以前 是无任何问题的,当前包因为新增很多纹理所以出现这个问题,但是在pad上不会出现,4上会频发。

内存一直是很关键的问题点,正常都是够的,但是总有低内存机子。所以一个是尽量进行纹理的优化,一个是加载配置要合理,没用的了该删要删。这总是一件蛮麻烦的工作。

谢谢斑竹,的确,本来想着体验,纹理都是预加载进入内存,但是现在纹理太多,估计只能加载UI纹理了,其他的用的时候加载,用完释放。

有时候出问题的我倒是希望程序直接crash,而不是还在健壮的跑,然后其他地方报奇怪的错误,需要优化的终究需要优化。