Memory 在Lua中通过引用删除变量
我在几张桌子里找到了几件东西。 多个功能更改对象并将其移交给其他功能 假设我的桌子是这样的:Memory 在Lua中通过引用删除变量,memory,lua,reference,lua-table,Memory,Lua,Reference,Lua Table,我在几张桌子里找到了几件东西。 多个功能更改对象并将其移交给其他功能 假设我的桌子是这样的: objectTable = {obj1, obj2, obj3} otherobjTable = {objA, objB, objC, objD} 假设这些都是在main.lua中初始化的 现在,当跟踪obj1时,它被一个函数改变,这个函数改变了它,并给出了对另一个函数的引用,这个函数再次改变了它。 一个步骤可能看起来像: function() if something then func(ob
objectTable = {obj1, obj2, obj3}
otherobjTable = {objA, objB, objC, objD}
假设这些都是在main.lua中初始化的
现在,当跟踪obj1时,它被一个函数改变,这个函数改变了它,并给出了对另一个函数的引用,这个函数再次改变了它。
一个步骤可能看起来像:
function()
if something then func(obj_1)
elseif something else then func(obj_2)
elseif something other then func(obj_3)
//... and so on...
end
function func(received_Object)
if something then
table.insert(received_Object, a value)
end
callAnotherFunction(received_Object)
end
function callAnotherFunction(received_Object)
if input == "Delete it" then
local name = received_Object.name
received_Object = nil
return string.format("%s was deleten", name)
else
return false
end
end
现在的问题是,在接收到\u Object=nil后,参考点为nil,但对象仍然存在。如何确保删除它?在Lua中,某些类型(如表)总是通过引用传递,而其他类型(如数字)总是通过值传递
此外,Lua是一种由垃圾收集器管理内存的语言。垃圾收集器删除一个对象(例如,一个表),而不再有对它的引用(让我们称之为锚定)
现在这个代码:
local t = {}
local t1 = {t}
someFunc(t)
为该表创建三个定位点。当someFunc
将另一个表作为参数传递给另一个函数时,将创建第四个锚点(以该函数的局部变量/参数的形式)
为了让垃圾收集器扫描第一个表,必须删除所有这些引用(通过赋值nil
或超出范围)
重要的是要理解,当您将nil
分配给本地t
时,并不意味着该表将被删除。更糟糕的是,对该表的所有引用都将无效。这意味着你只是在释放这一个锚,这只是当时四个锚中的一个
可能的解决方案
一种可能的解决方案是在保存对象的表中传递索引/键,该索引/键存储对象:
function func(myTable, myKey)
...
end
现在,如果在此函数中执行以下操作:
myTable[myKey] = nil
(并且不会创建其他锚点),键下的对象将不再有指向它的引用,并且将被标记为在下一轮垃圾收集器进行扫描。当然,callAnotherFunction
也必须以同样的方式进行修改:
callAnotherFunction(myTable, myKey)
...
end
如果在这些函数中对该对象执行许多操作,则可以将其缓存到局部变量中,以避免多次查找表。这是正常的,因为当函数完成时,锚定将与局部变量一起清除:
callAnotherFunction(myTable, myKey)
local myObj = myTable[myKey]
...
if myCondition then myTable[myKey] = nil end
end --here myObj is no longer valid, so the anchor is gone.
另一种解决方案
由于您不能像上面建议的那样对代码进行太多的更改,因此可以实现以下逻辑:
为包含对象的表创建元表:
local mt = {
__newindex = function(tab, key, val)
--if necessary and possible, perform a check, if the value is in fact object of your type
val.storeTableReference(tab, key) --you'll have to implement this in your objects
rawset(tab, key, val);
end
}
local container1 = setmetatable({}, mt)
local container2 = setmetatable({}, mt)
现在,在该表中插入对象时:
container1.obj1 = obj1
container2.obj1 = obj1
每次_newindex元方法都将调用带有适当引用的obj1.storeTableReference
。此函数将这些引用存储在(例如)一个内部表中
唯一需要实现的是对象的方法,该方法释放这些引用:
myObj:freeReferences = function()
for k, v in ipairs(self:tableReferences) do --assuming that's where you store the references
k[v] = nil
end
tableReferences = {} --optional, replaces your reference table with an empty one
end
现在这个解决方案有点笨拙,因为有几件事你需要小心:
仅在首次创建密钥时触发get。所以\uuuu newindex
和container1.obj=obj1
只会 在第一次赋值时触发container1.obj=obj2
。解决办法是 首先将\uuu newindex
键设置为nil,然后设置为obj
obj2
- 当您在该表中将
手动设置为nil(或另一个 对象),您需要确保对象存储的引用 也会被清除obj
delete
方法,该方法迭代这些表,并将适当的键设置为nil
。通过在表插入中使用\uuu newindex
元方法在插入时存储这些引用,这可以在表插入中半自动化。也许weak
表也可以是一个解决方案-不知道您的项目就很难判断。这听起来很棒。在我的例子中,这可能会更容易实现,因为更改每个参数。如果你愿意在你的答案中加入这个想法,我将把它标记为解决方案。谢谢。很好的解释,但是你使用了流行语“按参考传递”和“按价值传递”。不要引起混乱,但这不是计算机科学和C++语言如何使用术语。这是一个漫长的讨论。