quick cocos2dx lua 內存釋放

前言

  對於內存的優化,網上有不少例子和教程。整體來講,就那麼幾種解決方案,在最後我會簡單提下,這裏先說下在quick中,對於圖片的處理。html

1.查看內存調試信息

  對於quick框架的瞭解,咱們能夠參考\docs\文件夾裏面的文件,有相關api。學會學習的第一步,就是學會看api。好了,廢話很少說,下面是和內存相關的地方。android

可是在這裏我不說具體再項目中怎麼使用了,相信各位大神們一看就明白,有錯誤的地方,更好的,請大神們分享一下。ios

在項目的config.lua中有些調試信息的設置,這裏簡單說下。api

在初始化框架以前,能夠定義如下常量:數組

  • DEBUG: 設置框架的調試輸出級別緩存

    DEBUG = 0 -- 不輸出任何調試信息(默認值) DEBUG = 1 -- 輸出基本的調試信息 DEBUG = 2 -- 輸出詳細的調試信息 
  • DEBUG_FPS: 設置是否在畫面中顯示渲染幀率等信息框架

    DEBUG_FPS = false -- 不顯示(默認值) DEBUG_FPS = true -- 顯示 
  • DEBUG_MEM: 設置是否輸出內存佔用信息異步

    DEBUG_MEM = false -- 不輸出(默認值) DEBUG_MEM = true -- 每 10 秒輸出一次 
  • LOAD_DEPRECATED_API: 是否載入過期的 API 定義,默認爲 falseasync

  • DISABLE_DEPRECATED_WARNING: 使用過期的 API 時是否顯示警告信息,默認爲 true學習

  • USE_DEPRECATED_EVENT_ARGUMENTS: 是否使用過期的 Node 事件參數格式,默認爲 false

上面標紅的就是咱們要用的,能夠在調試信息中看到內存的使用狀況。

2.SceneEx.lua

  Scene的自動清理更能,實現原理是exit的時候,遍歷autoCleanupImages_數組,而後調用

display.removeSpriteFrameByImageName(imageName)進行釋放,咱們能夠把須要在場景切換時釋放掉的圖片,經過
Scene:markAutoCleanupImage放到scene的autoCleanupImages_中。詳細代碼以下:
local c = cc
local Scene = c.Scene

function Scene:setAutoCleanupEnabled()
    self:addNodeEventListener(c.NODE_EVENT, function(event)
        if event.name == "exit" then
            if self.autoCleanupImages_ then
                for imageName, v in pairs(self.autoCleanupImages_) do
                    display.removeSpriteFrameByImageName(imageName)
                end
                self.autoCleanupImages_ = nil
            end
        end
    end)
end

function Scene:markAutoCleanupImage(imageName)
    if not self.autoCleanupImages_ then self.autoCleanupImages_ = {} end
    self.autoCleanupImages_[imageName] = true
    return self
end

3.display.lua

  對於圖片的批處理、批量加載、合成大圖加載、下降圖片的質量等,在display中,有方法的封裝和介紹。

-- start --

--------------------------------
-- 將指定的 Sprite Sheets 材質文件及其數據文件載入圖像幀緩存。
-- @function [parent=#display] addSpriteFrames
-- @param string plistFilename 數據文件名
-- @param string image 材質文件名
-- @see Sprite Sheets


--[[--

將指定的 Sprite Sheets 材質文件及其數據文件載入圖像幀緩存。

格式:

display.addSpriteFrames(數據文件名, 材質文件名)

~~~ lua

-- 同步加載紋理
display.addSpriteFrames("Sprites.plist", "Sprites.png")

-- 異步加載紋理
local cb = function(plist, image)
    -- do something
end
display.addSpriteFrames("Sprites.plist", "Sprites.png", cb)

~~~

Sprite Sheets 通俗一點解釋就是包含多張圖片的集合。Sprite Sheets 材質文件由多張圖片組成,而數據文件則記錄了圖片在材質文件中的位置等信息。

]]
-- end --

function display.addSpriteFrames(plistFilename, image, handler)
    local async = type(handler) == "function"
    local asyncHandler = nil
    if async then
        asyncHandler = function()
            local texture = sharedTextureCache:getTextureForKey(image)
            assert(texture, string.format("The texture %s, %s is unavailable.", plistFilename, image))
            sharedSpriteFrameCache:addSpriteFrames(plistFilename, texture)
            handler(plistFilename, image)
        end
    end

    if display.TEXTURES_PIXEL_FORMAT[image] then
        cc.Texture2D:setDefaultAlphaPixelFormat(display.TEXTURES_PIXEL_FORMAT[image])
        if async then
            sharedTextureCache:addImageAsync(image, asyncHandler)
        else
            sharedSpriteFrameCache:addSpriteFrames(plistFilename, image)
        end
        cc.Texture2D:setDefaultAlphaPixelFormat(cc.TEXTURE2D_PIXEL_FORMAT_RGBA8888)
    else
        if async then
            sharedTextureCache:addImageAsync(image, asyncHandler)
        else
            sharedSpriteFrameCache:addSpriteFrames(plistFilename, image)
        end
    end
end

-- start --

--------------------------------
-- 從內存中卸載 Sprite Sheets 材質和數據文件
-- @function [parent=#display] removeSpriteFramesWithFile
-- @param string plistFilename 數據文件名
-- @param string image 材質文件名

-- end --

function display.removeSpriteFramesWithFile(plistFilename, imageName)
    sharedSpriteFrameCache:removeSpriteFramesFromFile(plistFilename)
    if imageName then
        display.removeSpriteFrameByImageName(imageName)
    end
end

-- start --

--------------------------------
-- 設置材質格式。
-- @function [parent=#display] setTexturePixelFormat
-- @param string filename 材質文件名
-- @param integer format 材質格式
-- @see Texture Pixel Format


--[[--

設置材質格式。

爲了節約內存,咱們會使用一些顏色品質較低的材質格式,例如針對背景圖使用 cc.TEXTURE2D_PIXEL_FORMAT_RGB565 格式。

display.setTexturePixelFormat() 能夠指定材質文件的材質格式,這樣在加載材質文件時就會使用指定的格式。

]]
-- end --

function display.setTexturePixelFormat(filename, format)
    display.TEXTURES_PIXEL_FORMAT[filename] = format
end

-- start --

--------------------------------
-- 從圖像幀緩存中刪除一個圖像。
-- @function [parent=#display] removeSpriteFrameByImageName
-- @param string imageName 圖像文件名

--[[--

從圖像幀緩存中刪除一個圖像。

有時候,某些圖像僅在特定場景中使用,例如背景圖。那麼在場景退出時,就能夠用 display.removeSpriteFrameByImageName() 從緩存裏刪除再也不使用的圖像數據。

此外,Scene 提供了 markAutoCleanupImage() 接口,能夠指定場景退出時須要自動清理的圖像,推薦使用。

]]
-- end --

function display.removeSpriteFrameByImageName(imageName)
    sharedSpriteFrameCache:removeSpriteFrameByName(imageName)
    cc.Director:getInstance():getTextureCache():removeTextureForKey(imageName)
end

-- start --

--------------------------------
-- 從指定的圖像文件建立並返回一個批量渲染對象。
-- @function [parent=#display] newBatchNode
-- @param string image 圖像文件名
-- @param integer capacity
-- @return SpriteBatchNode#SpriteBatchNode ret (return value: cc.SpriteBatchNode) 
-- @see Batch Node

--[[--

從指定的圖像文件建立並返回一個批量渲染對象。

~~~ lua

local imageName = "Sprites.png"
display.addSpriteFrames("Sprites.plist", imageName) -- 載入圖像到幀緩存

-- 下面的代碼繪製 100 個圖像只用了 1 次 OpenGL draw call
local batch = display.newBatchNode(imageName)
for i = 1, 100 do
    local sprite = display.newSprite("#Sprite0001.png")
    batch:addChild(sprite)
end

-- 下面的代碼繪製 100 個圖像則要使用 100 次 OpenGL draw call
local group = display.newNode()
for i = 1, 100 do
    local sprite = display.newSprite("#Sprite0001.png")
    group:addChild(sprite)
end

~~~

]]
-- end --

function display.newBatchNode(image, capacity)
    return cc.SpriteBatchNode:create(image, capacity or 100)
end

-- start --

--------------------------------
-- 建立並返回一個圖像幀對象。
-- @function [parent=#display] newSpriteFrame
-- @param string 圖像幀名稱
-- @return SpriteFrameCache#SpriteFrameCache ret (return value: cc.SpriteFrameCache) 

--[[--

建立並返回一個圖像幀對象。

~~~ lua

display.addSpriteFrames("Sprites.plist", "Sprites.png")

-- 建立一個 Sprite
local sprite = display.newSprite("#Yes.png")

-- 建立一個圖像幀
local frameNo = display.newSpriteFrame("No.png")

-- 在須要時,修改 Sprite 的顯示內容
sprite:setSpriteFrame(frameNo)

~~~

]]
-- end --

function display.newSpriteFrame(frameName)
    local frame = sharedSpriteFrameCache:getSpriteFrame(frameName)
    if not frame then
        printError("display.newSpriteFrame() - invalid frameName %s", tostring(frameName))
    end
    return frame
end

-- start --

--------------------------------
-- 以特定模式建立一個包含多個圖像幀對象的數組。
-- @function [parent=#display] newFrames
-- @param string pattern 模式字符串
-- @param integer begin 起始索引
-- @param integer length 長度
-- @param boolean isReversed 是不是遞減索引
-- @return table#table ret (return value: table)  圖像幀數組


--[[--

以特定模式建立一個包含多個圖像幀對象的數組。

~~~ lua

-- 建立一個數組,包含 Walk0001.png 到 Walk0008.png 的 8 個圖像幀對象
local frames = display.newFrames("Walk%04d.png", 1, 8)

-- 建立一個數組,包含 Walk0008.png 到 Walk0001.png 的 8 個圖像幀對象
local frames = display.newFrames("Walk%04d.png", 1, 8, true)

~~~

]]
-- end --

function display.newFrames(pattern, begin, length, isReversed)
    local frames = {}
    local step = 1
    local last = begin + length - 1
    if isReversed then
        last, begin = begin, last
        step = -1
    end

    for index = begin, last, step do
        local frameName = string.format(pattern, index)
        local frame = sharedSpriteFrameCache:getSpriteFrame(frameName)
        if not frame then
            printError("display.newFrames() - invalid frame, name %s", tostring(frameName))
            return
        end

        frames[#frames + 1] = frame
    end
    return frames
end

-- start --

--------------------------------
-- 以包含圖像幀的數組建立一個動畫對象。
-- @function [parent=#display] newAnimation
-- @param table frames 圖像幀的數組
-- @param number time 每一楨動畫之間的間隔時間
-- @return Animation#Animation ret (return value: cc.Animation)  Animation對象

--[[--

以包含圖像幀的數組建立一個動畫對象。

~~~ lua

local frames = display.newFrames("Walk%04d.png", 1, 8)
local animation = display.newAnimation(frames, 0.5 / 8) -- 0.5 秒播放 8 楨
sprite:playAnimationOnce(animation) -- 播放一次動畫

~~~

]]
-- end --

function display.newAnimation(frames, time)
    local count = #frames
    -- local array = Array:create()
    -- for i = 1, count do
    --     array:addObject(frames[i])
    -- end
    time = time or 1.0 / count
    return cc.Animation:createWithSpriteFrames(frames, time)
end

-- start --

--------------------------------
-- 以指定名字緩存建立好的動畫對象,以便後續反覆使用。
-- @function [parent=#display] setAnimationCache
-- @param string name 名字
-- @param Animation animation 動畫對象

--[[--

以指定名字緩存建立好的動畫對象,以便後續反覆使用。

~~~ lua

local frames = display.newFrames("Walk%04d.png", 1, 8)
local animation = display.newAnimation(frames, 0.5 / 8) -- 0.5 秒播放 8 楨
display.setAnimationCache("Walk", animation)

-- 在須要使用 Walk 動畫的地方
sprite:playAnimationOnce(display.getAnimationCache("Walk")) -- 播放一次動畫

~~~

]]
-- end --

function display.setAnimationCache(name, animation)
    sharedAnimationCache:addAnimation(animation, name)
end

-- start --

--------------------------------
-- 取得以指定名字緩存的動畫對象,若是不存在則返回 nil。
-- @function [parent=#display] getAnimationCache
-- @param string name
-- @return Animation#Animation ret (return value: cc.Animation) 

-- end --

function display.getAnimationCache(name)
    return sharedAnimationCache:getAnimation(name)
end

-- start --

--------------------------------
-- 刪除指定名字緩存的動畫對象。
-- @function [parent=#display] removeAnimationCache
-- @param string name

-- end --

function display.removeAnimationCache(name)
    sharedAnimationCache:removeAnimation(name)
end

-- start --

--------------------------------
-- 從內存中卸載沒有使用 Sprite Sheets 材質
-- @function [parent=#display] removeUnusedSpriteFrames

-- end --

function display.removeUnusedSpriteFrames()
    sharedSpriteFrameCache:removeUnusedSpriteFrames()
    sharedTextureCache:removeUnusedTextures()
end

-- start --

--------------------------------
-- 建立一個進度條的節點
-- @function [parent=#display] newProgressTimer
-- @param mixed image
-- @param number progressType

--[[--

建立一個進度條的節點

進度條類型有:

- display.PROGRESS_TIMER_BAR
- display.PROGRESS_TIMER_RADIAL 環形

]]

-- end --

3.項目內存優化

  對於整個項目的內存優化,咱們能夠在下面幾個方面。cocos2dx一直在更新和優化,因此,不要僅侷限於下面的解決方案,只是其中的一部分,

也許有的版本已經再也不適應,請根據你所使用的版本和項目的具體需求,作出優化方案。

(1)紋理優化

上面咱們講到了quick中的優化,下面還有其餘幾個解決辦法

爲了優化紋理內存的使用,咱們必須知道什麼因素影響了內存的使用狀況。

有三個因素影響了紋理的內存使用。紋理格式(壓縮的仍是非壓縮的),顏色,大小。

咱們可使用PVR格式的紋理來減小內存使用。最被建議的紋理格式是pvr.ccz,每色的bit值越高,畫面質量就約好。可是也會消費不少內存。

那麼咱們使用顏色深度是RGBA4444的紋理來代替RBGA8888,這將會消費一半內存。

咱們也會發現大紋理也會致使內存相關的問題。那麼你最好使用適度的大小。

推薦個圖片壓縮的網站:

https://tinypng.com/

(2)音頻

有三個因素影響文件內存使用。是音頻文件格式,比特率,和樣本率

咱們最但願音頻文件時mp3格式。由於它被android和ios都支持。而且它也被壓縮而且硬件加速了。

你應該保證你的背景音樂文件大小在800KB一下。最簡單的方式就是減小背景音樂播放時間而且重複調用。

你應該保持你的音頻文件樣本率在96-128kbps之間,而且比特率在44kHz就足夠了。

(3)字體和粒子系統優化

這裏咱們有兩個建議:當使用BM字體顯示遊戲分數,在你的圖片文件中選擇最小的數字字符,例如:

若是你想只顯示數字,你能夠移除全部的字符。

粒子系統中,咱們能夠減小粒子數量來減小內存使用。

(4)語言代碼

  無內存泄露的代碼。

  lua 注意全局變量的使用 ,局部變量不要忘記 local

最後一些建議:

一、一幀幀的加載遊戲資源。

二、減小繪製調用

三、按照最大到最小的順序的加載紋理

四、避開內存使用高峯、

五、使用加載界面來預加載遊戲資源。

六、當不須要的時候釋放無用的資源

七、當有內存警告的時候釋放緩存的資源

八、使用texturePacker來優化紋理尺寸,格式,色彩深度值等等。

九、當心使用JPG文件

十、使用16位RBGA4444色彩深度的紋理(看具體的機型,Android和IOS有點卻別)

十一、使用NPOT紋理代替POT紋理

十二、避開加載大尺寸圖片

1三、使用1024*1024 NPOT pvr.ccz紋理圖集而不是原生圖片

有些的不對的地方和須要完善的地方,但願大神指教。

本文地址:http://www.cnblogs.com/zhangfeitao/p/4562791.html

相關文章
相關標籤/搜索