Cocos2d-x释放资源的最佳时机

发表于2016-05-15
评论1 2k浏览
  有场景A跟场景B,场景A是当前场景,场景B是将要替换的新场景。那么A场景的资源释放最佳时机是在什么时候呢?
  这是释放资源的代码(注意要按这个顺序释放):
  CCAnimationCache::purgeSharedAnimationCache();
  SpriteFrameCache::getInstance()->removeUnusedSpriteFrame();
  CCTextureCache::getInstance()->removeUnusedTextures();
  CCTextureCache::getInstance()->getCachedTextureInfo();
  1、最开始我想到的,应该是在场景A的onExit里释放,试验了下,资源并没有被释放,说明当前纹理仍然在被引用,即场景A的子节点并未remove。后来查了下,发现每个场景的资源释放都是在一个叫dealloc的方法里,而这个方法是在onExit之后执行的。也就是说在onExit里释放资源是不合适的做法。
  2、我突然想起来,每个类不都有个析构函数么?析构函数是在该类的对象被delete时调用的,只要在A场景的析构函数里释放不就可以了?试验了下,发现也没效果,仔细想想,我创建场景用的方法是Cocos2DX推荐的默认方法,即场景类继承一个Layer,然后再createScene里创建一个Scene,再把当前类添加到Scene里。替换场景后,该Layer被释放时,场景中的其他资源并不一定被释放,所以此方法也是行不通的。
  3、竟然场景真正remove子节点是在dealloc方法里,那么在dealloc里释放资源不就好?
  可惜的是我根本就找不到有这个方法。于是放弃了。
  后来百度了下场景的调用顺序规则:
replaceScene : SceneB
init : SceneB
onExitTransitionDidStart : SceneA
onExit : SceneA
dealloc : SceneA
onEnter : SceneB
onEnterTransitionDidFinish : SceneB
  由此可看出,B场景的onEnter函数在A场景的dealloc之后执行。
  而且那么只要在B场景的onEnter里释放A场景的资源就可以。
  试验了下,资源的确被释放了。
  而且,释放资源是在B场景的init之后执行,这样的好处就是,假设场景B中用到场景A中的某些资源,
  这些资源就不会被释放再加载,造成不必要的内存高峰。
  4、问题到此结束了吗?我也以为结束了,然后又发现新问题。一旦我给场景过渡加上效果,以上方法就不灵验了,释放失败。
  Director::getInstance()->replaceScene(CCTransitionFade::create(0.5f, SceneB::createScene()));
  然后调试跟踪下执行顺序,发现问题所在了。
  当有过渡效果存在的时候,执行顺序变成这样:
replaceScene : SceneB
init : SceneB
onExitTransitionDidStart : SceneA
onEnter : SceneB
onExit : SceneA
onEnterTransitionDidFinish : SceneB
  没错,场景A并不会立刻结束,而是等到动画效果完毕后才结束。
  但是我发现不管有没有使用过渡动画,最后执行的总是onEnterTransitionDidFinish,
  那么我们只要将资源释放放在这里就行了。
  经过试验,发现又失败了。。。
  为啥,因为虽然dealloc方法是在onExit之后执行,但并不是紧追其后,也就是说,
  有可能在onEnterTransitionDidFinish 之前,也有可能在其后,因此我们直接在
  onEnterTransitionDidFinish 里释放资源并不一定可行。那该怎么解决?
  这里我使用了延时释放的方法,在onEnterTransitionDidFinish 执行后过一段时间,
  再调用释放资源的方法,这样就可以确保资源被释放。
  scheduleOnce(CC_SCHEDULE_SELECTOR(SceneB::release), 2.0f);
  5、以上方法的确是可以将资源释放掉,但是不是我们所要的”最佳时机”呢?
  仔细观察,B场景的init是在A场景的释放之前的,也就是说,在B场景诞生,A场景彻底释放的短时间内,会存在A,B场景的所有资源共存的现在。这个时候内存达到巅峰。如果A场景跟B场景的资源所占内存都非常大的时候,或许会造成崩溃。那么我们应该如何解决?目前我的解决方法就是在场景过渡的时候增加一个过渡场景,也就是Loading场景,Loading场景本身所需的资源并不多,在A场景资源释放完毕后,再开启B场景的资源加载。
  来源网址:http://www.cocoachina.com/bbs/read.php?tid-309621.html

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引