cocos2d-x與ios記憶體管理分析

firedragonpzy發表於2012-08-18
一、IOS與圖片記憶體
在IOS上,圖片會被自動縮放到2的N次方大小。比如一張1024*1025的圖片,佔用的記憶體與一張1024*2048的圖片是一致的。圖片佔用記憶體大小的計算的公式是;長*寬*4。這樣一張512*512 佔用的記憶體就是 512*512*4 = 1M。其他尺寸以此類推。(ps:IOS上支援的最大尺寸為2048*2048)。


二、cocos2d-x 的圖片快取
Cocos2d-x 在構造一個精靈的時候會使用spriteWithFile或者spriteWithSpriteFrameName等 無論用哪種方式,cocos2d-x都會將這張圖片載入到快取中。如果是第一次載入這個圖片,那就會先將這張圖片載入到快取,然後從快取讀取。如果快取中已經存在,則直接從快取中提取,免除了載入過程。

圖片的快取主要由以下兩個類來處理:CCSpriteFrameCache, CCTextureCache

CCSpriteFrameCache載入的是一張拼接過的大圖,每一個小圖只是大圖中的一個區域,這些區域資訊都在plist檔案中儲存。用的時候只需要根據小圖的名稱就可以載入到這個區域。

CCTextureCache 是普通的圖片快取,我們所有直接載入的圖片都會預設放到這個快取中,以提高呼叫效率。
因此,每次載入一張圖片,或者通過plist載入一張拼接圖時,都會將整張圖片載入到記憶體中。如果不去釋放,那就會一直佔用著。


三、渲染記憶體。
不要以為,計算記憶體時,只計算載入到快取中的記憶體就可以了。以一張1024*1024的圖片為例。
CCSprite *pSprite = CCSprite::spriteWithFile("a.png");

呼叫上邊這行程式碼以後,可以在LEAKS工具中看到,增加了大約4M的記憶體。然後接著呼叫
addChild(pSprite);

這時,記憶體又增加了4M。也就是,一張圖片,如果需要渲染的話,那它所佔用的記憶體將要X2。

再看看通過plist載入的圖片,比如這張大圖尺寸為2048*2048。想要載入其中的一張32*32的小圖片
CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("b.plist");
此時記憶體增加16M (汗)
CCSprite *pSpriteFrame = CCSprite::spriteWithSpriteFrameName("b1.png");
b.png 大小為32*32 ,想著也就是增加一點點記憶體,可實際情況是增加16M記憶體。也就是隻要渲染了其中的一部分,那麼整張圖片都要一起被載入。

但是情況不是那麼的糟糕,這些已經渲染的圖片,如果再次載入的話,記憶體是不會再繼續升高的,比如又增加了100個b.plist的另一個區域,圖片記憶體還是共增加16+16 = 32M,而不會繼續上升。


四、快取釋放
如果遊戲有很多場景,在切換場景的時候可以把前一個場景的記憶體全部釋放,防止總記憶體過高.
CCTextureCache::sharedTextureCache()->removeAllTextures(); 釋放到目前為止所有載入的圖片
CCTextureCache::sharedTextureCache()->removeUnusedTextures(); 將引用計數為1的圖片釋放掉CCTextureCache::sharedTextureCache()->removeTexture(); 單獨釋放某個圖片
CCSpriteFrameCache 與 CCTextureCache 釋放的方法差不多。
值得注意的是釋放的時機,一般在切換場景的時候釋放資源,如果從A場景切換到B場景,呼叫的函式順序為B::init()---->A::exit()---->B::onEnter() 。
可如果使用了切換效果,比如CCTransitionJumpZoom::transitionWithDuration這樣的函式,則函式的呼叫順序變為B::init()---->B::onEnter()---->A::exit() 。
而且第二種方式會有一瞬間將兩個場景的資源疊加在一起,如果不採取過度,很可能會因為記憶體吃緊而崩潰。
有時強制釋放全部資源時,會使某個正在執行的動畫失去引用而彈出異常,可以呼叫CCActionManager::sharedManager()->removeAllActions();來解決。


五、記憶體優化
優化的心得就是儘量去拼接圖片,使圖片邊長儘可能的保持2的N次方並且裝的很滿。但要注意,有邏輯關係的圖片儘量打包在一張大圖裡,另外一點就是打包的時候要考慮到層的分佈。因為為了渲染效率可能會用到CCSpriteBatchNode;同一個BatchNode裡的圖片都是位於一個層級的,因此必須根據各個圖片的層級關係,打包到不同的plist裡。有時記憶體和效率不可以兼得,只能儘量平衡了。


六、其他
最後附一個各代IOS裝置的記憶體限制情況
裝置 建議記憶體 最大記憶體
iPad2/iPhone4s/iphone4 170-180mb 512mb
iPad/iPod touch3,4/iphone3gs 40-80mb 256mb
iPod touch1,2/iPhone3g/iPhone1 25mb 128mb
上述建議記憶體只是一些人自己測試的結果,可用的RAM不大於最大記憶體的一半,如果程式超過最大記憶體的一半,則可能會掛掉。
另外在LEAKS裡檢視模擬器中和真機總的記憶體,會有較大出入。在模擬器中的結果與實際更接近一些。

摘自:[url]http://www.firedragonpzy.com.cn/index.php/archives/1206[/url]

相關文章