在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
lua内存泄露首先第一点,lua中的内存泄露和我们所说的c/c++中的内存泄露本质上是不一样的。lua中有垃圾回收机制(GC),所以理论上是不会有内存泄露的。当它进行GC的时候,会从根部开始扫描所有的对象,如果某个地方对这个对象还有引用,就不会把这个对象内存collect,这个对象就没有被GC。所以lua中的内存泄露是指那些:已经没有被使用了,但外部依然还有引用存在的对象。
以下是一些常见的错误引用情景: 解决方法: 可以建立一个weak table, 把你所有创建过的能够称之为资源的,包含但不限于“战斗对象,玩家,npc,物品,场景,邮件”等等对象全部扔到这个table里面。当你知道玩家 知道有泄漏是比较容易的,能够完全揪出来就不是很容易了。是的,它究竟在哪儿呢? 一开始在此项目里面也是先发现比如某npc泄漏了,然后就去查代码,看看究竟哪个地方写得不对。这种方式效率极低,基本上查不到什么问题。在迟一点的时候才使用现在的方案:从_G深度遍历所有的table、metatable、funciton's upvalue、function's env、registentry(lua_ref)。
目前所知的所有引用必定存在于这几个空间, 遍历完成以后一定可以找到那个“迷失了的引用”。 这种方式在脚本层就可以完成所有事情,甚至你可以在运营环境中在线查证,其遍历的速度是非常快的,但内存开销非常大(:,可以考虑一边遍历一边gc,当然还要记得避免重复搜索。 在应用此方案以后,此项目解决了脚本中所有的泄漏问题。 检测原理lua中支持垃圾回收机制的对象有五种:string,table,function,full userdata,thread。而他们的引用直接或间接的保存到:lua_state对象,_G全局表,Registry注册表,global_state->mt中。 在脚本中: 运行的lua脚本本身就是lua_state。_G就是_G全局表。Registry表可以用debug.getregistry获取。global_mt可以用debug.getmetatable获取。所以我们就可以在脚本层次实现内存泄露的检测模块。在搜索时需要注意的几点: table 额外搜索metatable,若metatable中的__mode取值为”k"、"v"或者”kv"需特殊处理(补充中有说明); function 额外搜索 enviroment,也是一个table; 额外搜索upvalues,这个可以是任何类型。由于userdata在script层次不能被修改,所以搜搜他的metatable吧thread对象就是coroutine对象,在script中一般都不会创建多个coroutine,所以在脚本中没搜索它。若是需求的话,获取到它的线程函数,然后再按照第2步操作就可以了。搜索流程图(_G表)检测泄露之前,先搜索一下所有的对象,保存好起始的内存状态,在程序执行之后执行几次GC操作,然后再进行一次搜索,对比两次的结果,多出来的那些就有可能是内存泄露了。 __mode 赋值为 "k", "v"或者”kv",表示保存在它中的键或值或键值都是一种弱引用状态。若一个对象的所有引用都是弱引用了,那么这个对象也会被GC回收掉,所以对应的weak表中此对象的入口就没有了。 所以我们可以用另外一种实现:就是把用户自己创建的资源对象统统都丢到weak表中,运行完程序后强制GC,然后去查看weak表,若表中还保存着那个对象,就意味着这个对象还有外部引用(相对弱引用我们就叫它为强引用吧),资源没有被GC掉,所以我们可以说这个对象很有可能是内存泄露了。( 为了发现内存泄漏,我们可以创建一个全局的弱引用table,使其key为弱引用,然后在每次创建那些可能存在泄漏的对象的时候,都放入这个table,让其作为key,value通常我会用当前时间。由于弱引用的性质,如果其他引用都消失了,那么在弱引用table中对这个对象的引用也会消失(变成nil),反之,只要还有其它任何一个引用存在,这个弱引用表中对这个对象的引用就继续存在。依赖这个特性,当程序已经跑过释放对象的逻辑后,如果这个表中还存在有这个对象的引用,那么这个对象肯定就是泄漏了。) Lua垃圾回收算法Lua的GC算法使用的所谓“Mark And Sweep”算法。简单的理解,这个算法将GC分为两个阶段,一个是标记(mark)阶段,这一阶段将所有系统中引用的对象都逐一标记;而在清理(sweep)阶段,将把在mark阶段中没有被标记的数据删除。 在Lua中,使用几种颜色来区分不同的结点: white:白色表示没有进行过标记的节点 gray:灰色表示已经进行过标记的节点,但是与它相关联的节点还没有进行过标记。 black:本节点和与之关联的节点都已经被扫描标记过了。通常会出现有关联数据的,包括有Table,upvalue等数据类型。 垃圾收集器函数collectgarbage函数提供了多项功能:停止垃圾回收,重启垃圾回收,强制执行一次回收循环,强制执行一步垃圾回收,获取Lua占用的内存,以及两个影响垃圾回收频率和步幅的参数。collectgarbage(opt,[,arg])
垃圾回收器有两个参数用于控制它的节奏: 第一个参数,称为暂停时间,控制回收器在完成一次回收之后和开始下次回收之前要等待多久; 第二个参数,称为步进系数,控制回收器每个步进回收多少内容。粗略地来说,暂停时间越小、步进系数越大,垃圾回收越快。这些参数对于程序的总体性能的影响难以预测,更快的垃圾回收器显然会浪费更多的CPU周期,但是它会降低程序的内存消耗总量,并可能因此减少分页。只有谨慎地测试才能给你最佳的参数值。 [转自]http://www.2cto.com/kf/201502/377646.html---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Lua教程之弱引用table这次要介绍的内容比较少,就一个——弱引用table 1.无法超越人类智慧的智能——自动内存管理的缺陷 我们都知道,Lua是具备自动内存管理的,好吧,也许有些朋友不知道。 我们只管创建对象,无须删除对象(当然,对于不要的对象你需要设置一下nil值),Lua会自动删除那些被认为是垃圾的对象。 问题就出现在,什么对象才是垃圾对象,有些时候,我们很清楚某个对象是垃圾,但是,Lua却无法发现。
复制代码 代码如下:
然后创建一个新的table——key1,这个key1作为t的key值,给t新增了一个字段,赋值为1。 同样的,key2也作为t的一个key值。 接着,调用了collectgarbage函数,可以不管它,我们只要知道,它会让lua进行一次垃圾回收。 最后输出t的所有字段,输出结果如下:
复制代码 代码如下:
这很符合常理,也在我们的预计当中,虽然我们在给t赋值之后,key1和key2都赋值为nil了。 但是,已经添加到table中的key值是不会因此而被当做垃圾的。 换句话说,key1本身已经是nil值,但它曾经所指向的内容依然存放在t中。key2也是一样的情况。 所以我们最后还是能输出key1和key2的name字段。 2.颠覆你的认知——弱引用table 刚刚举例的只是正常情况,那么,如果我们把某个table作为另一个table的key值后,希望当table设为nil值时,另一个table的那一条字段也被删除。 应该如何实现? 这时候就要用到弱引用table了,弱引用table的实现也是利用了元表。 我们来看看下面的代码,和之前几乎一样,只是加了一句代码:
复制代码 代码如下:
留意,在t被创建后,立刻给它设置了元表,元表里有一个__mode字段,赋值为”k”字符串。 如果这个时候大家运行代码,会发现什么都没有输出,因为,t的所有字段都不存在了。 一旦其他地方对于key值的引用取消了(设置为nil),那么,这个table里的这个字段也会被删除。 随后,又执行了key1 = nil,此时,除了t本身以外,就没有任何地方对key1保持引用,所以t的key1字段也会被删除。 3.三种形式的弱引用 对于弱引用table,其实有三种形式: 1)key值弱引用,也就是刚刚说到的情况,只要其他地方没有对key值引用,那么,table自身的这个字段也会被删除。设置方法:setmetatable(t, {__mode = “k”}); [转自]http://www.ogeek.NET/article/55229.htm 下面是一个网友检测lua内存泄漏的代码,可以参考一下,转自:Lua内存泄漏应对方法.
全部评论
专题导读
热门推荐
热门话题
阅读排行榜
|
请发表评论