Corona中文站

强大、易学的跨平台(iOS/Android)开发框架。QQ群1:74390406(满) 群2:221929599

导航

使用Corona SDK 时如何防止内存泄漏

一谈到使用Corona SDK创建一个应用程序时,内存管理已经成为敏感的问题。为什么?因为每个人都知道需要内存管理且都知道这是很重要的,但不是每个人都知道怎么去很好的管理它,并成为了一个烦扰你的问题,我的应用程序泄漏内存了吗?

首先…

神马是内存管理

对于Corona项目来说这并不是什么新的问题。不管你用什么框架、什么语言来开发应用程序你都不得不去管理内存。

如果你使用的是Lua和Corona,幸运的是你只需要关心逻辑部分的内存管理,不需要考虑技术上的——因为Lua的垃圾回收机制会自动的帮你管理内存。

在Corona中仅仅管理下面的五项内容就能很好的实现内存管理

1.对象(Display objects)
2.全局变量(Global variables)
3.监听器(Runtime listeners)
4.定时器(Timers)
5.Transitions

如果你不能很好的管理上面的五项内容,那你就会遇到严重的内存泄漏问题。有没有什么方法可以追踪内存泄漏呢?有各种各样的方法可以做到,但最简单的方法是把下面的代码放到你的main.lua的底部(或者是放在其他的地方,只要你喜欢):

local monitorMem = function()
    collectgarbage()
    print( "MemUsage: " .. collectgarbage("count") )

    local textMem = system.getInfo( "textureMemoryUsed" ) / 1000000
    print( "TexMem:   " .. textMem )
end

Runtime:addEventListener( "enterFrame", monitorMem )

上面的代码会在你的控制台中连续的打印两行:

> MemUsage: ##

> TextMem: ##

第一行表示的是Lua的内存,第二行表示的是Corona内存(主要是图形)。数量并不是最重要的。重要的是当你的屏幕进行切换时,那个数量会适当的上升和下降。

例如,当你切换到另一个屏幕时,这取决于在屏幕上的内存会上升或下降。假定是上升。那么当你返回到上一个屏幕时内存再次上升了。这就表示存在内存泄漏,因为内存的使用量要返回到上一个屏幕所使用的值。从某种意义上说,一些东西被困在内存中了。

请牢记上面提到的小函数,因为它是一个实用的捕获内存泄漏的小工具。事实上,使用相同的以上功能,我已经能够有效处理错误和崩溃的程序(没有100%的崩溃,所以换句话说,我不会再崩溃了)。

你可能会注意到上面一个叫collectgarbage()的方法。它是用Lua方法实现的一个垃圾回收器。而且它会把内存中没用的变量释放出来。Lua会自动为你做这些事,但当你需要时也可以强制执行collectgarbage( “collect” )。

1.对象

对象是非常容易管理的,因为你直接负责创建对象。确保你已经将不再使用的变量移除,这种方法可以有效阻止因对象引起的内存泄漏。

例如:

display.remove( redBall )
redBall = nil

注意:为什么我使用display.remove()代替removeSelf(仅供参考,这两种方法是一样的,调用removeSelf前display.remove()会先检查确定对象不再是空的。在Corona中这只是移除对象的一个安全的方式)

在这部分中经常出现泄漏的是当循环的创建对象或者其他的地方很难跟踪每一个独立的对象。只是要确保你追踪任何对象,从某种意义上说,特别是当改变屏幕时,显示对象不再使用时从内存中被释放。

2.全局变量

全局变量是在定义时没有在前面加上local。建议你要尽可能的不使用全局变量,但如果确实有用的话,确保不再使用时把它的值设为nil,这样Lua的垃圾回收器就能释放它的内存。

想对如何利用local的习惯有更多的了解请看之前我发布的局部变量教程。

3.监听器

当你移除对象时,与之对应的监听器也从内存释放了。然而,当你为Runtime添加监听器(如enterFrame listeners)时,直到你手动的移除它们,不然是不会被释放的。

一个普遍的泄漏发生于Runtime/ enterFrame的是,当一个开发者为特殊的屏幕添加一个Runtime,但他们离开屏幕时忘记删除事件监听器。接下来会发生什么呢?当用户离开屏幕,然后他们回来的时候,总有两个相同的Runtime监听器处在运行中。

有时,这就产生了彻底的崩溃。有时,你的应用程序会陷于泥淖最终崩溃。这些结果不是我们期待的。

5.Timers and Transitions

Timers and Transitions 可能是崩溃的其中一个最常见的原因,主要是因为无数的事件可以发生在timer/transition开始和结束之间。更糟糕的是,当你不在使用时忘记了去取消他们,它们可能会被困在内存中并引起更多的泄漏。

有一种方法,你能管理好它们,把所有的timers and transitions储存在表中,以便当你确定没有timers and transitions应该运行时,你可以立即取消他们。

如果你添加下列代码到你的main.lua文件(或另一个模块然后require它),你可以轻松地追踪你的timers and transitions并且在需要的时候立刻取消它们:

timerStash = {}
transitionStash = {}

function cancelAllTimers()
    local k, v

    for k,v in pairs(timerStash) do
        timer.cancel( v )
        v = nil; k = nil
    end

    timerStash = nil
    timerStash = {}
end

--

function cancelAllTransitions()
    local k, v

    for k,v in pairs(transitionStash) do
        transition.cancel( v )
        v = nil; k = nil
    end

    transitionStash = nil
    transitionStash = {}
end

然后,当你创建一个新的timer or transition时,首先分配到各自的表中,就像这样:

timerStash.newTimer = timer.performWithDelay( ...

transitionStash.newTransition = transition.to( myObject { ...

那么你可以同时使用 cancelAllTimers() and cancelAllTransitions()方法来停止所有的timers和transitions。如果有的timers不想取消,那么一开始就不要添加到存储表中(但可别忘了取消它)。

在无数的解决方案中这仅是一个你能做的方法。你可能总是手动控制它们,这也是很好的。

总结

注意,我没有提到任何关于指针或任何其他与内存管理有关的东西?只是简单的、实用的建议了下,如果你一如既往的在Corona SDK中应用这些,将帮助你开发出稳定、健壮的程序。

 

<< 每周之星【2011.8.14】 - MixZle独立开发者应重视快速迭代的开发技巧 >>

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

最近发表

Powered By Z-Blog 1.8 Walle Build 100427 Copyright 2011-2015 BuildApp.Net. All Rights Reserved.