lua 弱引用有什么用以及在xlua中的应用
一、简单介绍1、lua的GC默认是自动回收的,当一个对象的引用计数为0时,它就会被GC所回收。
2、lua中的表默认是强引用的,当你把某个对象放入表中时,就是生成一个对它的强引用(对象的引用计数+1),在对象的引用计数没有为0之前不会被GC回收;
3、如果把一个表声明为弱引用,则当把某个对象放如表中时,生成一个弱引用(对象不会被引用计数,可以理解为引用计数+0);如果一个对象只被弱引用表所引用(对象的引用计数为0),则会被下一次GC自动回收
所以弱引用表weak table的用途一般都是出于GC考虑的
注意:以上所指对象不包括值类型:number、boolean
二、使用
可以通过重写元方法__mode来定义一个表为弱引用表weak table,它包含三个值:"k"、"v"、"kv",如下所示:
k 标记表的key为弱引用
v 标记表的value为弱引用
kv同时标记表的key和value为弱引用
三、例子
local defaults = {}
setmetatable(defaults, {__mode='v'})
local value1 = {}
local value2 = {}
defaults["key1"] = value1
defaults["key2"] = value2
value2 = nil
collectgarbage()
for k,v in pairs(defaults) do
print(k,'\t',v)
end
执行上述代码后输出如下
key1 table: 0x600003b90900
设置弱引用后,以 value2 为值的数据从defaults中被垃圾回收了。
如果屏蔽setmetatable(defaults, {__mode='k'}),执行代码输出如下:
key2 table: 0x600000bf8880
key1 table: 0x600000bf8900
四、在xlua中 lua调用C#对象是如何保证对象不会回收的?又是什么时机释放的呢?
C#和Lua都是有自动垃圾回收机制的,并且相互是无感知的。如果传递到Lua的C#对象被C#自动回收掉了,而Lua这边仍毫不知情继续使用,则必然会导致无法预知的错误。所以基本原则是传递到Lua的C#对象,C#不能自动回收,只能Lua在确定不再使用后通知C#进行回收
为了保证C#不会自动回收对象,所有传递给Lua的对象都会被objects保持引用。真实传递给Lua的对象索引就是对象在objects中的索引
Lua这边为对象索引建立的userdata会被保存在缓存表中,而缓存表的引用模式被设置为弱引用
// ObjectTranslator.cs
LuaAPI.lua_newtable(L);// 创建缓存表
LuaAPI.lua_newtable(L);// 创建元表
LuaAPI.xlua_pushasciistring(L, "__mode");
LuaAPI.xlua_pushasciistring(L, "v");
LuaAPI.lua_rawset(L, -3);// 元表 = v,表示这张表的所有值皆为弱引用
LuaAPI.lua_setmetatable(L, -2);// 为缓存表设置元表
cacheRef = LuaAPI.luaL_ref(L, LuaIndexes.LUA_REGISTRYINDEX);
当Lua这边不再引用这个userdata时,userdata会被从缓存表中移除,Lua GC时会回收这个userdata,回收之前又会调用userdata元表的__gc方法,以此来通知C#层对C#对象的引用,这时C#对象就会再下一次垃圾回收时被回收掉。
在BeginObjectRegister方法内部,会为userdata的元表添加__gc方法
// Utils.cs BeginObjectRegister方法
if ((type == null || !translator.HasCustomOp(type)) && type != typeof(decimal))
{
LuaAPI.xlua_pushasciistring(L, "__gc");
LuaAPI.lua_pushstdcallcfunction(L, translator.metaFunctions.GcMeta);
LuaAPI.lua_rawset(L, -3);// 为元表设置__gc方法
}
translator.metaFunctions.GcMeta实际上就是StaticLuaCallbacks的LuaGC方法
// StaticLuaCallbacks.cs
public static int LuaGC(RealStatePtr L)
{
try
{
int udata = LuaAPI.xlua_tocsobj_safe(L, 1);
if (udata != -1)
{
ObjectTranslator translator = ObjectTranslatorPool.Instance.Find(L);
if ( translator != null )
{
translator.collectObject(udata);
}
}
return 0;
}
catch (Exception e)
{
return LuaAPI.luaL_error(L, "c# exception in LuaGC:" + e);
}
}
LuaGC方法又会调用collectObject方法。在collectObject方法内部会将对象从objects移除,从而使对象不再被固定引用,能够被C# GC正常回收
// ObjectTranslator.cs
internal void collectObject(int obj_index_to_collect)
{
object o;
if (objects.TryGetValue(obj_index_to_collect, out o))
{
objects.Remove(obj_index_to_collect);
if (o != null)
{
int obj_index;
//lua gc是先把weak table移除后再调用__gc,这期间同一个对象可能再次push到lua,关联到新的index
bool is_enum = o.GetType().IsEnum();
if ((is_enum ? enumMap.TryGetValue(o, out obj_index) : reverseMap.TryGetValue(o, out obj_index))
&& obj_index == obj_index_to_collect)
{
if (is_enum)
{
enumMap.Remove(o);
}
else
{
reverseMap.Remove(o);
}
}
}
}
}
以上就是弱引用在xlua中的应用,希望对大家有所帮助。
页:
[1]