Lua采用了基于垃圾收集的内存管理机制,因此对于程序员来说,在很多时候内存问题都将不再困扰他们。然而任何垃圾收集器都不是万能的,在有些特殊情况下,垃圾收集器是无法准确的判断是否应该将当前对象清理。这样就极有可能导致很多垃圾对象无法被释放。为了解决这一问题,就需要Lua的开发者予以一定程度上的配合。比如,当某个table对象被存放在容器中,而容器的外部不再有任何变量引用该对象,对于这样的对象,Lua的垃圾收集器是不会清理的,因为容器对象仍然引用着他。如果此时针对该容器的应用仅限于查找,而不是遍历的话,那么该对象将永远不会被用到。事实上,对于这样的对象我们是希望Lua的垃圾收集器可以将其清理掉的。见如下代码:

a = {}
key = {}
a[key] = 1
key = {}
a[key] = 2
collectgarbage()
for k,v in pairs(a) do
print(v)
end

--输出1和2

在执行垃圾收集之后,table a中的两个key都无法被清理,但是对value等于1的key而言,如果后面的逻辑不会遍历table a的话,那么我们就可以认为该对象内存泄露了。在Lua中提供了一种被称为弱引用table的机制,可以提示垃圾收集器,如果某个对象,如上面代码中的第一个table key,只是被弱引用table引用,那么在执行垃圾收集时可以将其清理。

Lua是具备自动内存管理的,我们可以只管创建对象,无须删除对象(当然,对于不要的对象你需要设置一下nil值),Lua会自动删除那些被认为是垃圾的对象。

问题就出现在,什么对象才是垃圾对象,有些时候,我们很清楚某个对象是垃圾,但是,Lua却无法发现。正如上面所述,就需要Lua的开发者予以一定程度上的配合;再比如下面这个例子:

t = {};

-- 使用一个table作为t的key值
key1 = {name = "key1"};
t[key1] = 1;
key1 = nil; -- 又使用一个table作为t的key值
key2 = {name = "key2"};
t[key2] = 1;
key2 = nil; -- 强制进行一次垃圾收集
collectgarbage(); for key, value in pairs(t) do
print(key.name .. ":" .. value);
end

-- 其结果输出是:

key1:1

key2:1

这很符合常理,也在我们的预计当中,虽然我们在给t赋值之后,将key1和key2都赋值为nil了。

但是,因为存在table对key1,key2的引用,已经添加到table中的key值是不会因此而被当做垃圾的。

换句话说,key1本身已经是nil值,但它曾经所指向的内容依然存放在t中。key2也是一样的情况。

所以我们最后还是能输出key1和key2的name字段。

那么,如果我们把某个table作为另一个table的key值后,希望当table设为nil值时,另一个table的那一条字段也被删除。

应该如何实现?这时候就要用到弱引用table了,弱引用table的实现也是利用了元表。

Lua中的弱引用表提供了3中弱引用模式,即key是弱引用、value是弱引用,以及key和value均是弱引用。不论是哪种类型的弱引用table,只要有一个key或value被回收,那么它们所在的整个条目都会从table中删除。

一个table的弱引用类型是通过其元表的__mode字段来决定的。如果该值为包含字符"k",那么table就是key弱引用,如果包含"v",则是value若引用,如果两个字符均存在,就是key value弱引用。见如下代码:

a = {}
b = {__mode = "k"}
setmetatable(a,b)
key = {}
a[key] = 1
key = {}
a[key] = 2
collectgarbage()
for k,v in pairs(a) do
print(v)
end

--仅仅输出2

在上面的代码示例中,第一个key在被存放到table a之后,就被第二个key的定义所覆盖,因此它的唯一引用来自key弱引用表。事实上,这种机制在Java中也同样存在,Java在1.5之后的版本中也提供了一组弱引用容器,其语义和Lua的弱引用table相似。

最后需要说明的是,Lua中的弱引用表只是作用于table类型的变量,对于其他类型的变量,如数值和字符串等,弱引用表并不起任何作用。

备忘录(memoize)函数:

用“空间换时间”是一种通用的程序运行效率优化手段,比如:对于一个普通的Server,它接受到的请求中包含Lua代码,每当其收到请求后都会调用Lua的loadstring函数来动态解析请求中的Lua代码,如果这种操作过于频率,就会导致Server的执行效率下降。要解决该问题,我们可以将每次解析的结果缓存到一个table中,下次如果接收到相同的Lua代码,就不需要调用loadstirng来动态解析了,而是直接从table中获取解析后的函数直接执行即可。这样在有大量重复Lua代码的情况下,可以极大的提高Server的执行效率。反之,如果有相当一部分的Lua代码只是出现一次,那么再使用这种机制,就将会导致大量的内存资源被占用而得不到有效的释放。在这种情况下,如果使用弱引用表,不仅可以在一定程度上提升程序的运行效率,内存资源也会得到有效的释放。见如下代码:

local results = {}
setmetatable(results,{__mode = "v"}) --results表中的key是字符串形式的Lua代码
function mem_loadstring(s)
local res = results[s]
if res == nil then
res = assert(loadstring(s))
results[s] = res
end
return res
end

Lua table之弱引用的更多相关文章

  1. Lua弱引用table

    弱引用table 与python等脚本语言类似地,Lua也采用了自动内存管理(Garbage Collection),一个程序只需创建对象,而无需删除对象.通过使用垃圾收集机制,Lua会自动删除过期对 ...

  2. [Lua]弱引用table

    参考链接: http://www.benmutou.com/archives/1808 一.强引用table lua中的table是引用类型,更准确地说,是强引用类型.如下第二段代码,在内存中有一个{ ...

  3. Step By Step(Lua弱引用table)

    Step By Step(Lua弱引用table) Lua采用了基于垃圾收集的内存管理机制,因此对于程序员来说,在很多时候内存问题都将不再困扰他们.然而任何垃圾收集器都不是万能的,在有些特殊情况下,垃 ...

  4. Chapter 17_1 弱引用table

    Lua采用了自动内存管理.所以不用担心新创建的对象需要的内存如何分配出来,也不用考虑对象不再被使用后怎样释放它们所占用的内存. Lua实现了一个增量标记-扫描收集器.它使用这两个数字来控制垃圾收集循环 ...

  5. lua的弱弱引用表

    lua有GC.细节无需太关注.知道些主要的即可,能local就一定不要global: 还有在数组里的对象,除非显式=nil,否则非常难回收: 只是能够用弱引用表来告诉GC. 外部引用为0,就不要管我, ...

  6. 树形打印lua table表

    为方便调试lua程序,往往想以树的形式打印出一个table,以观其表内数据.以下罗列了三种种关于树形打印lua table的方法;法一 local print = print local tconca ...

  7. weak 弱引用的实现方式

    来源:冬瓜争做全栈瓜 链接:https://desgard.com/weak/ 对于 runtime 的分析还有很长的路,最近在写 block 系列的同时,也回顾一下之前疏漏的细节知识.这篇文章是关于 ...

  8. Lua table使用

    days = {"Sunday", "Monday", "Tuesday", "Wednesday", "Th ...

  9. lua table表

    lua table表 语法结构 创建一个 table 直接使用 "{}" 即可 table1 = {} -- 赋值 table1["name"] = " ...

随机推荐

  1. log4j:WARN Please initialize the log4j system properly 问题解决

    log4j:WARN No appenders could be found for logger (com.netease.qa.testng.TestngRetry).log4j:WARN Ple ...

  2. 一台电脑安装多个版本的jdk

    我们平时在做Java开发的时候,有时需要使用多个版本的jdk, 那么一台电脑上需要安装多个JDK了. 那一台电脑上可不可以同时安装多个版本的jdk呢? 答案是可以的! 但使用的时候,只能使用一个,不能 ...

  3. 【原】iOS学习之三种拨打电话方式的比较

    拨打电话小编从网上找到三种,在这里做一些总结和比较 1.基本使用 NSString *str = [[NSMutableString alloc] initWithFormat:@"tel: ...

  4. ElasticSearch问题记录

    1.Young GC导致集群master重新选举,一台server fail [2016-12-10 07:38:24,546][WARN ][transport ] [BFRD_1] Receive ...

  5. 我的Windows Phone 8

    学习Windows Phone 8开发,将自己收集到的学习资料做一个汇总(不断更新). 我的Windows Phone应用 DotaMax MyAppToStart 麦子学院 WP8.1版(UI简陋) ...

  6. CI框架使用PHPmail插件发送QQ邮件:

    有助请顶,不好请评.0:33 2016/3/12CI框架使用PHPmail插件发送QQ邮件:发送成功,不过修改了主机参数,还包含了一个phpmail中的一个另外的文件,详见下方:参见:http://c ...

  7. 从业十余年谈谈对dotnet看法与坚持

    前言 园子经常在讨论关于.Net发展的问题,我也这些年在工作乃至创业过程中使用.Net碰到的一些问题和看法.个人擅长的技术面,C/C++/MFC/STL.ASM.JAVA.VB.Javascript/ ...

  8. VIM 解决中文乱码

    $ vim ~/.vimrc 加入以下内容 set fileencodings=utf-8,ucs-bom,gb18030,gbk,gb2312,cp936 set termencoding=utf- ...

  9. 使用spring的@Scheduled注解执行定时任务,启动项目不输出警告

    在applicationContext.xml中添加: xmlns:task="http://www.springframework.org/schema/task" xsi:sc ...

  10. vs2013 手动生成webservice代理类wsdl

    第一步: 第二步: 第三步: 至此wsdl代理类生成成功!