cocos2d 性能優化1

  • 年前在對我做的項目做性能優化,雖然在開發中,性能問題是一直關注着的,但是這個東西依然需要在後期做一段時間的優化的,也遇到不少坑,在這裏分享下,也記作筆記,另外也歡迎大家有這方面的問題經驗在這裏討論。

    性能的優化主要是亮點,內存的優化和運行效率的優化

    1.內存的優化

    說內存的優化,首先要知道有什麼東西會佔據程序的內存,可優化的主要是兩部分:數據和資源,先說數據,做短連接的遊戲客戶端有兩種處理數據的方式:一種是傻瓜式客戶端,另一種是緩存式客戶端,傻瓜客戶端幾乎可以做到0數據,因爲他每個界面只是負責展示,當然,這個界面需要的數據是會存在客戶端的,但是他對內存的佔據是可以忽略的,基本也是不可優化的,除非你有內存泄露。另一種是客戶端會負責一些邏輯,它不僅有緩存的用戶數據,還有配置數據(策劃配置的遊戲數據),這些數據的大小有時甚至要超出你的想象(不會比圖少多少);再說資源,主要是圖和聲音,這兩種資源的優化處理只要掌握好如下原則就可以(同樣適用於數據)

    (1)不要對內存的釋放置之不理

    在j2me時代,由於沒有通用的引擎和框架,程序員實現界面切換時常會自覺地做無用資源的釋放,但是在智能機時代,這種“好習慣”由於系統的“強大”常常被人忽略;我見過不止一個項目的程序在使用cocos2d-x時是不考慮資源釋放的,因爲系統的自動回收機制,這點甚至有些線上項目都不會考慮;關於這點,你要知道的是,系統的內存回收機制是這樣的,他會有一個安全“臨界值”,注意這個值會小於系統的極限,每當到這個臨界值時系統會幫你清理你沒有泄露的內存,但是請不要過於相信這種方式,雖然臨界值小於最大值,假設臨界值是180m,最大值是200m,如果你進了一個場景,進場景之前是175,未到臨界值,但是這個界面加載了30m的東西,還沒等回收起作用,內存已經超過了最大的200m上限,這時肯定會崩潰,因此,保持主動地做無用資源的刪除是個好習慣。這個原則包括數據和資源

    (2) 隨用隨加載vs緩存

    既然要隨時刪除無用資源,那麼我們就不要任何緩存了吧?貌似這兩種方式就是對立的,也有人會說,隨用隨加載很浪費效率,沒錯,如果想處理好程序性能,這兩種方式真的不能對立來看,而是要結合起來用;對於圖片資源,我是這麼做的,每個界面都會用到的公用圖片我會放在一張圖片拼板中(或者是幾張),這些圖片會“常駐”內存,這個拼板會包括,常用的按鈕,背景,小圖標等等,這些圖片是緩存的,對於其他的圖片,一定要把這個界面用到的除公用圖片外的圖片打在一起,這樣,當進入這個界面的時候,只需要加載這些就可以,當離開界面時,需要把他們刪除,這些是隨用隨加載的,這個原則同樣用於數據當中,把常用的數據(加載時間會比較長的)讀入內存中,其他數據隨用隨加載,注意不用時要刪除,我也見過一些項目,數據是從來不清的,因此他們根本沒有最大內存的這個概念,內存會像雪球一樣,越滾越大,直到所有數據都在內存裏,這種做法和把所有數據都讀進來無異。

    (3)大圖片vs小碎圖?內存上限

    其實關於內存的大小,最不能突擊解決的就是“大圖片還是小碎圖”,這涉及到美術和程序的配合,程序的責任心等等,用大圖片,程序拼界面會比較省事,也會提高程序運行效率,但是小圖片會節約內存,當然這也有個度的問題,這就涉及到內存上限的問題,根據目前的設備,一般把內存控制到120左右是比較安全的,確定可執行的實際的內存上限目標也是比較重要的。

    除了這些原則,你還要直到cocos2d-x關於內存處理的一些“坑”

    (1)plist刪了,你的圖片真的刪了嗎?

    CCSpriteFrameCache中的removeSpriteFramesFromFile函數中傳入plist的名字就會刪除這個圖片的數據文件,具體的就是讀入plist文件時生成的字典,它只是解除了圖片的引用,但是刪除具體的圖片,需要調用CCTextureCache的removeUnusedTextures,注意,先調用前面的函數,後調用這個函數纔會起作用,需要注意的是,使用ccb是會幫你調用removeSpriteFramesFromFile的,另外removeSpriteFramesFromFile傳遞的plist的名字如果不存在,也會出問題,最好的辦法是改一下removeSpriteFramesFromFile,做一下容錯,另外最好是前一幀調用removeSpriteFramesFromFile,後一幀調用removeUnusedTextures和dumpCachedTextureInfo,這樣纔會起作用,因爲引用刪除後,纔會刪除他們引用的圖片

    (2)lua的內存泄露

    有時在遊戲中需要重新登錄,這時比較常用的處理方式是把CCLuaEngine::defaultEngine()指針指向的部分刪除,但是,這種粗暴的方式可能會造成一些內存泄露,需要在前面加入如下代碼

    1.pEngine->getLuaStack()->clean();
    2.lua_State *tolua_s = pEngine->getLuaStack()->getLuaState();
    3.lua_close(tolua_s);
    4.tolua_s = NULL;
    也就是說先要把棧中數據刪掉。

     

    (3)lua中table可能的內存泄露

    一般情況下,直接“table = nil”,在經過垃圾回收器的回收內存(lua這點類似java),就可以釋放內存了,但是,在有些特殊情況下,垃圾收集器是無法準確的判斷是否應該將當前對象清理。這樣就極有可能導致很多垃圾對象無法被釋放。這種情況就是交叉引用

     

    1.local table1 = {}
    2.local table2 = {}
    3.table2[1] = 1
    4.table1[table2[1]] = 1
    這種情況下在table2[1]被釋放前table1[table2[1]]不會釋放。

    2.運行效率的優化
    運行效率的優化是更加和遊戲邏輯緊密相關的,會根據不同的邏輯有不同的優化點,這裏也是記錄下一些原則:

    (1)減少在屏幕上繪製的元素

    屏幕繪製的元素多是運行效率低的最主要原因,cocos2d-x 3.0版本加強了繪製效率的優化,增加了自動裁剪和自動批處理,但是我們仍然要主動地減少在屏幕上繪製元素的方式,同樣和之前提到過的是大圖還是小圖的問題,這是需要平衡的,另外需要注意的是,有時候繪製的元素過多,是由於我們忘記了釋放無用的屏幕繪製元素,他們可能已經不再顯示(被遮擋),但是沒有被刪除

    (2)lua自動內存回收

    collectgarbage是lua自動回收的接口

     

    1.collectgarbage("setpause"100)
    2.collectgarbage("setstepmul"5000

     

    Lua 實現了一個增量標記清除的收集器。 它用兩個數字來控制垃圾收集週期: garbage-collector pause 和 garbage-collector step multiplier 。garbage-collector pause 控制了收集器在開始一個新的收集週期之前要等待多久。 隨着數字的增大就導致收集器工作工作的不那麼主動。 小於 1 的值意味着收集器在新的週期開始時不再等待。 當值爲 2 的時候意味着在總使用內存數量達到原來的兩倍時再開啓新的週期。step multiplier 控制了收集器相對內存分配的速度。 更大的數字將導致收集器工作的更主動的同時,也使每步收集的尺寸增加。 小於 1 的值會使收集器工作的非常慢,可能導致收集器永遠都結束不了當前週期。 缺省值爲 2 ,這意味着收集器將以內存分配器的兩倍速運行。

    只要設置了這個,你就不用在手動調用這個函數回收內存,手動調用會造成程序效率的降低

    (3)滾動列表的分頁處理

    滾動列表在遊戲中使用的比較頻繁,但是有一些是需要注意的,如果數據過多,需要採用分頁處理,不然列表裏地列表項也會過多,影響程序效率,另外tableview中採用的方法就是限制cell的個數,可以重用之前用過的cell,但是要注意的是,需要把原來cell中的數據清除

    (4)打印

    打印是很耗費效率的事情,最好在打包的時候用變量控制,屏蔽所有打印

    (5)分步加載

    有時一個界面要處理的東西過多,這時這個頁面顯示是需要分步處理,先展示一部分,效果會好些

    能想到的就是這些,再發現會在補充到這裏,歡迎討論

發佈了19 篇原創文章 · 獲贊 4 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章