cocos2dx 中切換場景內存佔用過高的處理
1、運行場景:
CCScene *pScene = HelloWorld::scene();
pDirector->runWithScene(pScene);
2、替換場景:
(1)
CCScene *pScene=SceneTestScene::scene();
CCDirector::sharedDirector()->replaceScene(pScene);
(2)
CCScene *pScene=SceneTestScene::scene();
CCDirector::sharedDirector()->pushScene(pScene);
(3)
CCScene *pScene=SceneTestScene::scene();
CCDirector::sharedDirector()->popScene(pScene);
3具體的代碼執行流程
假設scene A是活動場景,現在我們用scene B來pushScene替換A,A和B的生命週期是這樣的:
B ---- init();
A ---- onExit();
B ---- onEnter();
B ---- onEnterTransitionDidFinish();
此時popScene,彈出scene B,函數調用如下:
B ---- onExit();
B ---- 析構函數被調用
A ---- onEnter(); (並不會執行sceneA的init函數 ,因爲 pushScene的時候會執行sceneA的onExit函數釋放一些資源, 當pop的時候,不會執行init函數加載需要的資源,出現爲止的錯誤)
從上面可以看出以下幾點,
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();
4具體的引擎的執行代碼, 查看對象的生命週期。見下面的鏈接
http://blog.csdn.net/tonny_guan/article/details/28121973
-----------------華麗的分割線----------------
當使用replaceScene切換場景的時候,在遊戲所佔有的內存是當前內存峯值時多少哪,很可怕的
時當前場景的內存值,加上下一個場景的資源所佔用的內存值。
原因。。。。
在每個場景裏面會有一個init函數,一個onEnterTransitionDidFinish函數,一個Onexit函數,init實現一些初始化工作,onEnterTransitionDidFinish在init之後執行,Onexit在場景退出時回收init時分配的資源。在調試時發現一個很有趣的現象,那就是從場景一切換到場景二時,在切換的一瞬間會內存會非常高,但是過了一段時間後,內存會回到一個平穩的狀態,譬如切換時內存會達到80M,切換過後內存會降到50M。分析原因,懷疑是上一個場景的內存還沒有釋放,然後這一個場景的內存已經分配,所以兩個疊加在一起,就比較高了。所以我便在第一個場景的Onexit函數中加一個斷點,在第二個場景的init和onEnterTransitionDidFinish函數中各加一個斷點,然後運行程序,發現程序先到第二個場景的init中,然後再回到第一個場景的Onexit中,最後纔到第二個場景的onEnterTransitionDidFinish中。我才恍然大悟,原來在場景切換時,不是馬上會執行第一個場景的Onexit函數,而是先到第二個場景的init中加載資源,然後回到第一個場景中釋放資源,最後纔是到onEnterTransitionDidFinish中。
內存中的峯值很驚人。
方案一,
將必要的資源放在onEnter 中處理,其他的資源 放在onEnterTransitionDidFinish處理。
方案二
, 給場景切換添加一個過度場景,現在主流的rpg ,或者橫版格鬥的遊戲都已經這樣處理。 因爲資源量比較大,這樣處理高效並且安全。
--總結
1. 切換全屏場景的時候最好使用replaceScene而不是pushScene。
因爲pushScene並不會銷燬前一個scene,僅僅是將後一個scene按照堆棧的方式加入到前一個scene的上面。如果自身代碼中內存管理寫的不好的,利用pushScene很難發現該方面的問題,一旦崩潰定位都很難定位。replaceScene可以及早的將隱含的問題給暴露出來。
2. 儘量不要在onEnter裏面初始化精靈Sprite
這個就和上一條有點關係了,如果使用了pushScene,那麼再popScene的時候是不會調用前一個場景的init方法的(上一個界面的資源有的已經釋放,這時出現未知的錯誤),所以有同學就喜歡把一些初始化放在onEnter裏面,具體爲什麼不好,我們來看一下不同切換場景的時候,每個Scene的生命週期就知道了。