Lua弱引用table

弱引用table

与python等脚本语言类似地,Lua也采用了自动内存管理(Garbage Collection),一个程序只需创建对象,而无需删除对象。通过使用垃圾收集机制,Lua会自动删除过期对象。垃圾回收机制可以将程序员从C语言中常出现的内存泄漏、引用无效指针等底层bug中解放出来。

我们知道Python的垃圾回收机制使用了引用计数算法,当指向一个对象的所有名字都失效(超出生存期或程序员显式del了)了,会将该对象占用的内存回收。但对于循环引用是一个特例,垃圾收集器通常无法识别,这样会导致存在循环引用的对象上的引用计数器永远不会变为零,也就没有机会被回收。

一个在python中使用循环引用的例子:

class main1:
    def __init__(self):
        print(‘The main1 constructor is calling...‘)
    def __del__(self):
        print(‘The main1 destructor is calling....‘)

class main2:
    def __init__(self, m3, m1):
        self.m1 = m1
        self.m3 = m3
        print(‘The main2 constructor is calling...‘)
    def __del__(self):
        print(‘The main2 destructor is calling....‘)

class main3:
    def __init__(self):
        self.m1  = main1()
        self.m2 = main2(self, self.m1)
        print(‘The main3 constructor is calling...‘)
    def __del__(self):
        print(‘The main3 destructor is calling....‘)

# test
main3()
        

输出内容为:

The main1 constructor is calling...
The main2 constructor is calling...
The main3 constructor is calling...

可以看出,析构函数(__del__函数)没有被调用,循环引用导致了内存泄漏。

垃圾收集器只能回收那些它认为是垃圾的东西,不会回收那些用户认为是垃圾的东西。比如那些存储在全局变量中的对象,即使程序不会再用到它们,但对于Lua来说它们也不是垃圾,除非用户将这些对象赋值为nil,这样它们才能被释放。但有时候,简单地清除引用还不够,比如将一个对象放在一个数组中时,它就无法被回收,这是因为即使当前没有其他地方在使用它,但数组仍引用着它,除非用户告诉Lua这项引用不应该阻碍此对象的回收,否则Lua是无从得知的。

table中有key和value,这两者都可以包含任意类型的对象。通常,垃圾收集器不会回收一个可访问table中作为key或value的对象。也就是说,这些key和value都是强引用,它们会阻止对其所引用对象的回收。在一个弱引用table中,key和value是可以回收的。

弱引用table(weak table)是用户用来告诉Lua一个引用不应该阻碍对该对象的回收。所谓弱引用,就是一种会被垃圾收集器忽视的对象引用。如果一个对象的引用都是弱引用,该对象也会被回收,并且还可以以某种形式来删除这些弱引用本身。

弱引用table有3种类型:

1、具有弱引用key的table;
2、具有弱引用value的table;
3、同时具有弱引用key和value的table;

table的弱引用类型是通过其元表中的__mode字段来决定的。这个字段的值应为一个字符串:
如果包含‘k‘,那么这个table的key是弱引用的;
如果包含‘v‘,那么这个table的value是弱引用的;

弱引用table的一个例子,这里使用了collectgarbage函数强制进行一次垃圾收集:

a = {1,4, name=‘cq‘}

setmetatable(a, {__mode=‘k‘})

key = {}
a[key] = ‘key1‘

key = {}
a[key] = ‘key2‘

print("before GC")
for k, v in pairs(a) do
    print(k, ‘\t‘, v)
end

collectgarbage()

print("\nafter GC")
for k, v in pairs(a) do
    print(k, ‘\t‘, v)
end

输出:

before GC
1                       1
2                       4
table: 0x167ba70                        key1
name                    cq
table: 0x167bac0                        key2

after GC
1                       1
2                       4
name                    cq
table: 0x167bac0                        key2

在本例中,第二句赋值key={}会覆盖第一个key,当收集器运行时,由于没有地方在引用第一个key,因此第一个key就被回收了,并且table中的相应条目也被删除了。至于第二个key,变量key仍引用着它,因此它没有被回收。

注意,弱引用table中只有对象可以被回收,而像数字、字符串和布尔这样的“值”是不可回收的。

备忘录(memoize)函数是一种用空间换时间的做法,比如有一个普通的服务器,每当它收到一个请求,就要对代码字符串调用loadstring,然后再调用编译好的函数。不过,loadstring是一个昂贵的函数,有些发给服务器的命令有很高的频率,例如"close()",如果每次收到一个这样的命令都要调用loadstring,那还不如让服务器用一个辅助的table记录下所有调用loadstring的结果。

备忘录函数的例子:

local results = {}

setmetatable(results, {__mode=‘v‘})

function mem_loadstring(s)

    local res = results[s]

    if res == nil then
        res=assert(loadstring(s))
        results[s]=res
    end

    return res
end 

local a = mem_loadstring("print ‘hello‘")
local b = mem_loadstring("print ‘world‘")

a = nil

collectgarbage()

for k,v in pairs(results) do
    print(k, ‘\t‘, v)
end

例子中,table results会逐渐地积累服务器收到的所有命令及其编译结果。经过一定时间后,会耗费大量的内存。弱引用table正好可以解决这个问题,如果results table具有弱引用的value,那么每次垃圾收集都会删除所有在执行时未使用的编译结果。

lua元表一文中,提到过如何实现具有默认值的table。如果要为每一个table都设置一个默认值,又不想让这些默认值持续存在下去,也可以使用弱引用table,如下面的例子:

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 

local a = {}
local b = {}

setDefault(a, "hello")
setDefault(b, "world")

print(a.key1)
print(b.key2) 

b = nil
collectgarbage()

for k,v in pairs(defaults) do
    print(k,‘\t‘,v)
end
时间: 2024-10-07 18:29:15

Lua弱引用table的相关文章

Lua 弱引用table

本文转载于:http://www.benmutou.com/archives/1808 这次要介绍的内容比较少,就一个——弱引用table 1.无法超越人类智慧的智能——自动内存管理的缺陷 我们都知道,Lua是具备自动内存管理的,好吧,也许有些朋友不知道. 我们只管创建对象,无须删除对象(当然,对于不要的对象你需要设置一下nil值),Lua会自动删除那些被认为是垃圾的对象. 问题就出现在,什么对象才是垃圾对象,有些时候,我们很清楚某个对象是垃圾,但是,Lua却无法发现. 比如这样一个例子: t

(转载)【笨木头Lua专栏】基础补充22:弱引用table

这次要介绍的内容比较少,就一个--弱引用table 笨木头花心贡献,哈?花心?不,是用心~ 转载请注明,原文地址:http://www.benmutou.com/archives/1808 文章来源:笨木头与游戏开发 1.无法超越人类智慧的智能--自动内存管理的缺陷 我们都知道,Lua是具备自动内存管理的,好吧,也许有些朋友不知道. 我们只管创建对象,无须删除对象(当然,对于不要的对象你需要设置一下nil值),Lua会自动删除那些被认为是垃圾的对象. 问题就出现在,什么对象才是垃圾对象,有些时候

Chapter 17_1 弱引用table

Lua采用了自动内存管理.所以不用担心新创建的对象需要的内存如何分配出来,也不用考虑对象不再被使用后怎样释放它们所占用的内存. Lua实现了一个增量标记-扫描收集器.它使用这两个数字来控制垃圾收集循环:垃圾收集器间歇率 和 垃圾收集器步进倍率. 这两个数字都使用百分数为单位(例如:100在内部表示1) 前者表示控制收集器需要在开启新的循环前要等待多久,后者表示控制收集器运作速度相对于内存分配速度的倍率(不要设置为小于100,否则收集慢于分配). 在Lua中,你可以用弱引用和终结器作为垃圾回收的机

Lua程序设计 第17章 弱引用笔记

鉴于之前我对lua的评价,在此需要修改了一下我的言论:游戏开发语言工作中,最成熟的客户端开发组合:C/C++.Lua/C#.assembly汇编.C/C++系列用于完成游戏引擎框架,汇编用于优化,Lua负责游戏逻辑.在全局上满足了性能.可读性.变化性的需求.因为我选的是引擎方向,实际上只能吃透C/C++系列我才可能获得引擎 职位.另外推荐一本书<游戏引擎框架>-叶劲峰翻译的那本,并没有csdn某人读后感言"引擎水真深"的感觉.这本书写得好,可是那个废人却在叶劲峰的专访中说这

lua弱表引用

1.普通垃圾回收 --lua弱表,主要是删除key或者value是table的一种元方法 --元表里的__mode字段包含k或者v:k表示key为弱引用:v表示value为弱引用 local testa = {} tbl_key = {} testa[tbl_key] = 1 tbl_key = {} testa[tbl_key] = 2 --垃圾回收 collectgarbage() local function PrintInfo() for k, v in pairs(testa) do

lua的弱弱引用表

lua有GC,细节无需太关注,知道些基本的就行,能local就一定不要global: 还有在数组里的对象,除非显式=nil,否则很难回收: 不过可以用弱引用表来告诉GC.外部引用为0,就不要管我,请del it. weak table是通过元表实现,元表里的__mode字段包含k或者v:k表示key为弱引用:v表示value为弱引用. 1.首先看一个普通的例子: a = {} key = {} a[key] = 1 key = {} a[key]=2 collectgarbage() for k

lua中对象的弱引用

几次编写lua时.总是有同事遇到A中对象已经释放了.但B对象中A对象的值不是为空的. Lua的gc和Java的类似.只有当对象没有被引用时候才会释放这块内存.要想实现A释放了B中A的值也释放了这时候需要用到弱引用. setmetatable(t,{__mode="k"}); __mode 的值可以为"k","v","kv" ~ ~第一段代码中可以看到内存中是有一个[key]保存了一个table.虽然b=nil了但是t中还是存在

OC对象之旅 weak弱引用实现分析

Runtime源码分析带你了解OC实现过程.其中参考了大量的大神的代码以及文献里面也有个人的见解欢迎拍砖欢迎交流. 两种常见使用场景 /// weak属性@interface XX : [email protected](nonatomic,weak) Type* weakPtr;@end/// 代码块中使用{    /// 使用__weak     __weak Type* weakPtr = [[SomeObject alloc] init]; } 根据调试信息发现两者的区别是 第一种进入到

Torch-RNN运行过程中的坑 [1](读取Lua非空table,size为0)

0.踩坑背景 执行Torch-RNN的时候,在LanguageModel.lua中的encode_string函数中,对start_text的各个character进行id映射编码,实现功能类似"北京天安门"-->"5 10 88 32 111",方便后面的计算. 这个函数会利用一个全局的类似HashMap的table,hashmap中的key是character(char),value是id(int),涉及到一个从hashmap中按照key取值的操作,代码如