cocos2d-x场景切换时内存过高导致crash 解决方法

前端之家收集整理的这篇文章主要介绍了cocos2d-x场景切换时内存过高导致crash 解决方法前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

转自:http://www.jb51.cc/article/p-twljcjvs-x.html


最近在做一个cocos2d-x的项目时,遇到一个问题,就是在pc上运行都是ok的,可是在ipadandriod上面,在场景切换时时常会挂掉,用苹果自带Instruments工具检测时,发现在场景正常运行时,内存大概保持在三四十兆,但是在场景切换时,一瞬间会达到七八十兆,遇到一些素材比较多或者层比较多的场景,则会达到一百多兆。大家知道在ipad1上面,内存最大是128M,那么这个程序如果在ipad1上面运行,肯定会经常挂掉。遇到问题,只能一步步分析,一步步找。

1先把所有场景的retain的东西检查一遍,看看在Onexit的时候有没有release掉,这个检查完以后,还是会crash,所以这种情况不是根源。

2对于有好几个层的场景,在init的时候,先加载第一个层的,而不是把所有层的东西全部加载完,在切换层的时候再加载相对应的层,这种方法果然有效,当切换到这个场景的时候,内存果然减少了一半左右。但是对于只有一个层的场景来说,在切换时也是会挂,所以问题还没有找完全。

3我们知道,在每个场景里面会有一个init函数,一个onEnterTransitionDidFinish函数,一个Onexit函数init实现一些初始化工作,onEnterTransitionDidFinishinit后执行Onexit在场景退出时回收init时分配的资源。在调试时发现一个很有趣的现象,那就是从场景一切换到场景二时,在切换的一瞬间会内存会非常高,但是过了一段时间后,内存会回到一个平稳的状态,譬如切换时内存会达到80M,切换过后内存会降到50M。分析原因,怀疑是上一个场景的内存还没有释放,然后这一个场景的内存已经分配,所以两个叠加在一起,就比较高了。所以我便在第一个场景的Onexit函数中加一个断点,在第二个场景的initonEnterTransitionDidFinish函数中各加一个断点,然后运行程序,发现程序先到第二个场景的init中,然后再回到第一个场景的Onexit中,最后才到第二个场景的onEnterTransitionDidFinish中。我才恍然大悟,原来在场景切换时,不是马上会执行第一个场景的Onexit函数,而是先到第二个场景的init中加载资源,然后回到第一个场景中释放资源,最后才是到onEnterTransitionDidFinish中。

最终解决方法

把一些资源的初始化放到onEnterTransitionDidFinish中进行,那么究竟应该把那些资源放到onEnterTransitionDidFinish中初始化,而那些资源又只能放到init中呢?

1像背景图这种只能放到init中,像场景切换时要看到的一些精灵,必须放到init中,不然场景切换时会看不到背景或者一些精灵。

2象精灵的一些动画,动作,可以放到onEnterTransitionDidFinish中来初始化。

举个例子:

譬如一只船在划动,那么船这只精灵在场景切换时要展示,所以必须放在init

//小船精灵的加载

[cpp]view plaincopy

  1. m_boatAction=CCSprite::spriteWithFile(s1_little_boat1);

  2. addChild(m_boatAction);

  3. m_boatAction->setPosition(CCPointMake(s.width/2,s.height/2+130));

  4. m_boatAction->setScale(0.3);

  5. m_boatAction->retain();


而船划动的动作,就可以放到onEnterTransitionDidFinish来初始化和执行

[html]copy

  1. CCSizes=CCDirector::sharedDirector()->getWinSize();

  2. CCAnimation*animation=CCAnimation::animation();

  3. charframeName[100]={0};

  4. for(inti=1;i<=5;i++)

  5. {

  6. sprintf(frameName,"scene1/little_boat%d.png",i);

  7. animation->addFrameWithFileName(frameName);

  8. }

  9. CCActionInterval*action=CCAnimate::actionWithDuration(2,animation,false);

  10. repeatAction=CCRepeatForever::actionWithAction(action);

  11. repeatAction->retain();

通过这三步,基本上就可以避免在场景切换时内存过而导致crash的情况

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

转自:http://www.jb51.cc/article/p-auhuglmf-kp.html


最近在开发过程中遇到很多切换场景的时候概率性崩溃,内存暴增的问题。

因此总结一些开发中需要注意的要点,

1. 切换全屏场景的时候最好使用replaceScene而不是pushScene。

因为pushScene并不会销毁前一个scene,仅仅是将后一个scene按照堆栈的方式加入到前一个scene的上面。如果自身代码中内存管理写的不好的,利用pushScene很难发现该方面的问题,一旦崩溃定位都很难定位。replaceScene可以及早的将隐含的问题给暴露出来。

2. 尽量不要在onEnter里面初始化精灵Sprite

这个就和上一条有点关系了,如果使用了pushScene,那么再popScene的时候是不会调用前一个场景的init方法的,所以有同学就喜欢把一些初始化放在onEnter里面,具体为什么不好,我们来看一下不同切换场景的时候,每个Scene的生命周期就知道了。

假设scene A是活动场景,现在我们用scene B来pushScene替换A,A和B的生命周期是这样的:

B ---- init();

A ---- onExit();

B ---- onEnter();

B ---- onEnterTransitionDidFinish();

此时popScene,弹出scene B,函数调用如下:

B ---- onExit();

B ---- 析构函数调用

A ---- onEnter();

从上面可以看出以下几点,

1. A的析构函数始终未被调用,因此A一直在内存中。

2. 先执行B的init()函数,之后才调用A的onExit()方法,再之后才调用B的onEnter();所以初始化最好应该放在init中来初始化。在上一个场景退出之前初始化好后一个场景需要的资源。

同样的,我们再来看一下replaceScene切换场景,scene的生命周期

假设scene A是活动场景,现在我们用scene B来replaceScene替换A,A和B的生命周期是这样的:

B ---- init();

A ---- onExit();

A ---- 析构函数调用

B ---- onEnter();

B ---- onEnterTransitionDidFinish();


此时B replace A回来的调用跟上面一样,如下:

A ---- init();

B ---- onExit();

B ---- 析构函数调用

A ---- onEnter();


--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

还可以在a和b场景切换时,创建第三个场景来实现第二个场景所用资源的加载,这样可以减轻内存暴涨

猜你在找的Cocos2d-x相关文章