Lua中的weak表——weak table
弱表(weak table)是一个很有意思的东西,像C++/Java等语言是没有的。弱表的定义是:A weak table is a table whose elements are weak references,元素为弱引用的表就叫弱表。有弱引用那么也就有强引用,有引用那么也就有非引用。我们先要厘这些基本概念:变量、值、类型、对象。
(1)变量与值:Lua是一个dynamically typed language,也就是说在Lua中,变量没有类型,它可以是任何东西,而值有类型,所以Lua中没有变量类型定义这种东西。另外,Lua中所有的值都是第一类值(first-class values)。
(2)Lua有8种基本类型:nil、boolean、number、string、function、userdata、thread、table。其中Nil就是nil变量的类型,nil的主要用途就是一个所有类型之外的类型,用于区别其他7中基本类型。
(3)对象objects:Tables、functins、threads、userdata。对于这几种值类型,其变量皆为引用类型(变量本身不存储类型数据,而是指向它们)。赋值、参数传递、函数返回等都操作的是这些值的引用,并不产生任何copy行为。
Lua的垃圾回收机制:gc是很多语言的常见机制,让程序员拜托复杂易出错的内存管理。
定义:Lua manages memory automatically by running a garbage collector to collect all dead objects (that is, objects that are no longer accessible from Lua).
三点理解:(1)gc自动运行,也可以手动调用;(2)自动收集的目标是引用计数为0的对象;(3)dead objects:不能访问到的对象,没有引用指向它了,当然就是访问不到的了,也就等同于垃圾内存了。
weak table的定义:
(1)weak表是一个表,它拥有metatable,并且metatable定义了__mode字段;
(2)weak表中的引用是弱引用(weak reference),弱引用不会导致对象的引用计数变化。换言之,如果一个对象只有弱引用指向它,那么gc会自动回收该对象的内存。
(3)__mode字段可以取以下三个值:k、v、kv。k表示table.key是weak的,也就是table的keys能够被自动gc;v表示table.value是weak的,也就是table的values能被自动gc;kv就是二者的组合。任何情况下,只要key和value中的一个被gc,那么这个key-value pair就被从表中移除了( In any case, if either the key or the value is collected, the whole pair is removed from the table)。
对于普通的强引用表,当你把对象放进表中的时候,就产生了一个引用,那么即使其他地方没有对表中元素的任何引用,gc也不会被回收这些对象。那么你的选择只有两种:手动释放表元素或者让它们常驻内存。
strongTable = {}
strongTable[] = function() print("i am the first element") end
strongTable[] = function() print("i am the second element") end
strongTable[] = {, , } print(table.getn(strongTable)) --
collectgarbage()
print(table.getn(strongTable)) --
但是,在编程环境中,有时你并不确定手动给一个键值赋nil的时机,而是需要等所有使用者用完以后进行释放,在释放以前,是可以访问这个键值对的。这种时候,weak表就派上用场了。关于weak table的理解,看下面这个小例子:
weakTable = {}
weakTable[] = function() print("i am the first element") end
weakTable[] = function() print("i am the second element") end
weakTable[] = {, , } setmetatable(weakTable, {__mode = "v"}) -- 设置为弱表 print(table.getn(weakTable)) -- ele = weakTable[] -- 给第一个元素增加一个引用
collectgarbage()
print(table.getn(weakTable)) -- 1,第一个函数引用为1,不能gc ele = nil -- 释放引用
collectgarbage()
print(table.getn(weakTable)) -- 0,没有其他引用了,全部gc
当然在实际的代码过程中,我们不一定需要手动collectgarbage,因为该函数是在后台自动运行的,它有自己的运行周期和规律,对编程者来说是透明的。
注意:只有拥有显示构造的对象类型会被自动从weak表中移除,值类型boolean、number是不会自动从weak中移除的。而string类型虽然也由gc来负责清理,但是string没有显示的构造过程,因此也不会自动从weak表中移除,对于string的内存管理有单独的策略。
基于weak表的简单应用:
(1)记忆函数:一个相当普遍的编程技术是用空间来换取时间。你可以通过记忆函数结果来进行优化,当你用同样的参数再次调用函数时,它可以自动返回记忆的结果。将函数的输入和输出分别作为key和value放在一个weak table里面,调用函数之前先查看有无现成的结果,有就返回,没有就调用函数,然后将结果存入表中。由于是weak table,此表会定期自动清理掉不再有引用的键值对。
(2)关联对象属性:Lua本身使用这种技术来保存数组的大小。table库提供了一个函数来设定数组的大小,另一个函数来读取数组的大小。当你设定了一个数组的大小,Lua 将这个尺寸保存在一个私有的weak table,索引就是数组本身,而value就是它的尺寸。
同样的,当我们需要给任一对象添加一个属性的时候,可以在外部单独做一弱key表,然后以对象为key值,属性值为value。这样即可以方便的访问这个属性,也不影响该对象的释放。而且对象本身没任何修改,能很好的保持对象本身的独立性。
(3)带有默认值的表:
有两种实现方法,第一种方法,使用关联对象属性的方法,将表作为key,默认值作为value,存到一个弱key的weak表中:
local defaults = {}
setmetatable(defaults, {_mode = "k"}) local mt = {__index = function(t) return defaults[t] end} function setDefault(t, d)
defaults[t] = d
setmetatable(t, mt)
end
第二种方法,针对不同的metatable来进行优化,对于每一个具体的默认值,生成一个与之对应的metatable,然后以默认值为key,metatable为value,存到一个弱value的weak表中:
metas = {}
setmetatable(metas, {__mode = "v"}) setdefault = function (t, d)
local mt = metas[d]
if mt == nil then
mt = {__index = function() return d end}
metas[d] = mt
end
setmetatable(t, mt)
end
两种方式各有利弊,第一种方法对于每一个table都需要添加一个键值对,但是公用一个metatable。第二种方法需要许多个不同的metatable,但拥有相同默认值的table共用一个metatable,并且weak表要比第一种方法小。如果你的代码环境中有很多个table,但常用默认值只有那么几种,建议选择第二种方法,否则就选择第一种方法。
Lua中的weak表——weak table的更多相关文章
- Lua中的weak表——weak table(转)
弱表(weak table)是一个很有意思的东西,像C++/Java等语言是没有的.弱表的定义是:A weak table is a table whose elements are weak ref ...
- Openvswitch原理与代码分析(5): 内核中的流表flow table操作
当一个数据包到达网卡的时候,首先要经过内核Openvswitch.ko,流表Flow Table在内核中有一份,通过key查找内核中的flow table,即可以得到action,然后执行acti ...
- lua中,两种json和table互转方法的效率比较
lua中json和table的互转,是我们在平时开发过程中经常用到的.比如: 在用lua编写的服务器中,如果客户端发送json格式的数据,那么在lua处理业务逻辑的时候,必然需要转换成lua自己的数据 ...
- Lua中的元表与元方法
[前言] 元表对应的英文是metatable,元方法是metamethod.我们都知道,在C++中,两个类是无法直接相加的,但是,如果你重载了“+”符号,就可以进行类的加法运算.在Lua中也有这个道理 ...
- Lua中的元表与元方法学习总结
前言 元表对应的英文是metatable,元方法是metamethod.我们都知道,在C++中,两个类是无法直接相加的,但是,如果你重载了"+"符号,就可以进行类的加法运算.在Lu ...
- #在lua中的运用
在lua中"#"表示返回表长度或字符串长度 例子一: a = "Hello " b = "World" print("Concat ...
- Lua中的一些库(1)
[数学库] 数学库(math)由一组标准的数学函数构成.这里主要介绍几个常用的函数,其它的大家可以自行百度解决. 三角函数(sin,cos,tan……)所有的三角函数都使用弧度单位,可以用函数deg( ...
- Lua中的metatable详解
转自:http://www.jb51.net/article/56690.htm Lua 中 metatable 是一个普通的 table,但其主要有以下几个功能: 1.定义算术操作符和关系操作符的行 ...
- Lua弱表Weak table
定义:弱表的使用就是使用弱引用,很多程度上是对内存的控制. 1.weak表示一个表,它拥有metatable,并且metatable定义了__mode字段. 2.弱引用不会导致对象的引用计数变化.换言 ...
随机推荐
- XCode自动打ipa包脚本 命令
XCode 新建文件 选择other Shell script 放入下面命令行. #工程绝对路径 #cd $ project_path=$(pwd) #build文件夹路径 build_path=$ ...
- MyBatis crud操作
Test2.java package com.mycom.mybatis_1.crud; import java.util.List; import org.apache.ibatis.session ...
- checkbox的三种状态处理
checkbox只有两种值:选中(checked)或未选中(unchecked).它可以有任何值,但是表单提交时checkbox的值只能是checked或unchecked.它的默认值是uncheck ...
- 【迁移】—Entity Framework实例详解
好久没有在博客园更新博客了,如今都换了新公司.前段时间写了关于EF迁移的文档,今天拿出来作为这个系列的一篇吧. 一.Entity Framework 迁移命令(get-help EntityFrame ...
- How to apply Local Group Policy settings silently using the ImportRegPol.exe and Apply_LGPO_Delta.exe utilities.
参考:http://supportishere.com/how-to-apply-local-group-policy-settings-silently-using-the-importregpol ...
- 最近面试遇到的Windows相关的题目
上周准备在公司内部转岗,面了3个部门windows客户端相关的工作,最终拿到3个Offer,主要涉及C++和Windows两大块内容,C++的题目基本都答上了,Windows一直都是我的弱项,在这里记 ...
- mysql慢日志设置
mysql的慢日志查询对于sql的优化还是很有意义的,具体说下如何开启这个mysql慢查询日志(默认是开启的). 关于设置在mysql的官方手册或网上都有很多,但是要注意的是,mysql5.6与之前的 ...
- Android开发之蓝牙 --修改本机蓝牙设备的可见性,并扫描周围可用的蓝牙设备
一. 修改本机蓝牙设备的可见性 二. 扫描周围可用的蓝牙设备 一. 清单文件AdroidManifest.xml: <uses-permission android:name="an ...
- 【原创】开源BI领袖-SpagoBI5.X最详细的中文版介绍
SpagoBI是唯一100%的开源商业智能套件由 Engineering Group的SpagoBI实验室(www.eng.it)开发和管理.它提供了强大的分析能力,从传统的报表和图表功能到自助分析. ...
- A/B测试
昨天把前段时间开发的二胡调音器的应用发布到了亚马逊应用程序商店,看到了一个A/B测试的标签,了解一下A/B测试的工作原理. A/B测试是一种新兴的网页优化方法,可以用于增加转化率注册率等网页指标. 使 ...