quick cocos2dx lua 内存释放
前言
对于内存的优化,网上有很多例子和教程。总体来说,就那么几种解决方案,在最后我会简单提下,这里先说下在quick中,对于图片的处理。
1.查看内存调试信息
对于quick框架的了解,我们可以参考\docs\文件夹里面的文件,有相关api。学会学习的第一步,就是学会看api。好了,废话不多说,下面是和内存相关的地方。
但是在这里我不说具体再项目中怎么使用了,相信各位大神们一看就明白,有错误的地方,更好的,请大神们分享一下。
在项目的config.lua中有些调试信息的设置,这里简单说下。
在初始化框架之前,可以定义以下常量:
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 定义,默认为 false
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 )
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 =
local last = begin + length -
if isReversed then
last, begin = begin, last
step = -
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 + ] = 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
最后一些建议:
1、一帧帧的加载游戏资源。
2、减少绘制调用
3、按照最大到最小的顺序的加载纹理
4、避开内存使用高峰、
5、使用加载界面来预加载游戏资源。
6、当不需要的时候释放无用的资源
7、当有内存警告的时候释放缓存的资源
8、使用texturePacker来优化纹理尺寸,格式,色彩深度值等等。
9、小心使用JPG文件
10、使用16位RBGA4444色彩深度的纹理(看具体的机型,Android和IOS有点却别)
11、使用NPOT纹理代替POT纹理
12、避开加载大尺寸图片
13、使用1024*1024 NPOT pvr.ccz纹理图集而不是原生图片
有些的不对的地方和需要完善的地方,希望大神指教。
本文地址:http://www.cnblogs.com/zhangfeitao/p/4562791.html
quick cocos2dx lua 内存释放的更多相关文章
- cocos2d-x lua 内存回收
使用cocos2d-x lua架构,游戏中存在两种内存回收方式. 1.cocos2d-x 本身内存回收 PS:假设在lua在创建一个类,继承cocos2d-x的一个类A,则该A也遵循cocos2d-x ...
- quick Cocos2dx lua 接anysdk
quick3.3 的quick\samples\anysdk中有例子,具体用法可以参考官方文档,将的非常详细. 1.框架接口设计 系统介绍 必接入流程简要描述 消息通知 可扩展性 测试模式 添加测试账 ...
- quick cocos2dx lua 网络图片 下载 自己主动更新
转载请注明,原文地址:http://blog.csdn.net/dd135373/article/details/46468505 quick coocs2d-x 网络图片下载,自己主动更新纹理,保存 ...
- cocos2d-x之内存管理(4)
c++的内存管理一直以来都是个问题,也有多种实现方案,比如智能指针,使用引用计数等,cocos2d-x也需要涉及到内存的管理. cocos2d-x是如何管理内存的呢? cocos2d-x的内存管理主要 ...
- [置顶] 【玩转cocos2d-x之二十】从CCObject看cocos2d-x的内存管理机制
原创作品,转载请标明:http://blog.csdn.net/jackystudio/article/details/13765639 再看CCObject,剔除上节的拷贝相关,以及Lua脚本相关的 ...
- quick cocos2d-x 入门---井字棋
学习quick cocos2d-x 第二天 ,使用quick-x 做了一个井字棋游戏 . 我假设读者已经 http://wiki.quick-x.com/doku.php?id=zh_cn阅读了这个链 ...
- cocos2d-x + Lua接入iOS原生SDK的实现方案[转]
相信很多朋友在使用cocos2d-x+lua开发游戏时都遇到过接入iOS原生SDK的问题,比如常见的接应用内支付SDK,广告SDK或是一些社交平台SDK等等,我也没少接过这类SDK.这篇文章主要是对我 ...
- cocos2d-x 之 内存管理(5)
上一篇文件讲到了CCObject中实现的内存自动管理内存 下面介绍两个很重要的类,一个是内存池类 CCAutoReleasePool ,另一个类是内存池管理类 CCPoolManager 这两个类结合 ...
- cocos2dx的内存管理机制
首先我们必须说一下c++中变量的内存空间的分配问题,我们在c++中写一个类,可以在栈上分配内存空间也可以使用new在堆上分配内存空间,如果类对象是在栈上分配的内存空间,这个内存空间的管理就不是我们的事 ...
随机推荐
- Js分页插件,支持页面跳转
这里先给出API: 你只需要提供一个对象涉及以下几项属性,你来设置属性值,通过jq对象链式调用page()以参数形式来加载这个对象,按照参数要求会自动生成分页功能, 参数中pageEvent是可以让你 ...
- oracle结构与安全
从宏观上来看:oracle数据库服务器主要有数据库和实例组成. 在orale数据库服务器中,首先会产生一个实例,通过实例访问一个数据库. 一个实例对应着一个数据库. oracle 数据库在逻辑上是按层 ...
- Excel导出公共函数
/// <summary> /// 将一组对象导出成EXCEL /// </summary> /// <typeparam name="T">要 ...
- 浅谈scrum站立会议
什么是每日站立会议? 站立会议是让团队成员每日面对面站立互相交流他们所承担任务的进度.它的一个附带好处是让领导或经理能了解到工作情况.但本质上是为了团队交流,不是报告会议! 为什么开展每日 ...
- Wcf 双工通信的应用
概述 双工(Duplex)模式的消息交换方式体现在消息交换过程中,参与的双方均可以向对方发送消息.基于双工MEP消息交换可以看成是多个基本模式下(比如请求-回复模式和单项模式)消息交换的组合.双工ME ...
- 关于JAVA中的String的使用与连接(转)
JAVA中的String连接性能 Java中的String是一个非常特殊的类,使它特殊的一个主要原因是:String是不可变的(immutable). String的不可变性是Ja ...
- python - ConfigParser
ConfigParse 作用是解析配置文件. 配置文件格式如下 [test1]num1: 10[test2]num1: 35 配置文件两个概念section和option, 在这个例子中第一个sect ...
- 使用 readfile() 下载文件
下载图片 <?php $file = 'monkey.gif'; if (file_exists($file)) { header('Content-Description: File Tran ...
- Cocos2dx集成于windows桌面窗口程序的步骤
2D游戏需要做编辑器,而编辑器总是希望可以复用游戏中的逻辑来运行场景试看效果. 对于cocos2dx开发的程序,这个需求可以描述为: 实现一种方法,在桌面窗口程序中的某个控件上显示cocos2dx的场 ...
- js滚动加载插件
function $xhyload(o){ var that=this; if(!o){ return; }else{ that.win=$(o.config.obj); that.qpanel=$( ...