Xlua 和 c# 之间 gc 的原理
先说重点
- 这里是我输入给 chatgpt 的关键词
这里是我输入给gpt的关键词:
帮我生成一个mk的备忘录, 主要是讲清楚c#与lua之间的引用关系和原理以整个过程. 里面主要包括三个方面
1. c#引用lua对象时, c#侧luatable在调用Get<T>初始化方法时, 会在lua注册表(强引用表, luaL_ref(L, LUA_REGISTRYINDEX) )中增加对应table或function的引用计数, 保证lua侧不被gc, 最后在c#侧Dispose对象, 最后在lua侧走gc回收
2. lua引用c#对象时, c#侧会缓存入栈给lua的对象, 返回实际索引给lua, lua用弱表缓存(__mode = v)这个c#对象, 只要没有别的lua对象引用这个c#对象时, lua在gc时会走到原表里的__gc方法, 告诉c#这个对象lua不再使用, c#在gc时回收自己的对象
3. 所有避免gc的操作都是操作内存的, 对应操作byte[]的句柄不要忘记自己回收
剩下你觉得有什么事重要的东西夜整合进去, 然后所有东西都整合在一个mk里 我直接发在csdn上
- 注意以下所有内容均为chatgpt生成, 不确认是否说的对
C#与Lua之间的引用关系
1. C# 引用 Lua 对象
1.1 引用过程
在C#中引用Lua对象时,通常通过LuaTable
或LuaFunction
等方式进行管理。C#侧会在Lua注册表中增加对应table或function的引用计数,以保证Lua侧不被GC回收。这是通过luaL_ref(L, LUA_REGISTRYINDEX)
实现的。
1.2 实现细节
- 使用
luaL_ref
将 Lua 对象存储在注册表中,并返回一个引用 ID。 - 通过引用 ID,C# 可以在需要时获取 Lua 对象。
- 在 C# 侧不再需要该 Lua 对象时,调用
Dispose
方法,释放引用,并减少引用计数。 - Lua 对象在引用计数为零后,会被 Lua 的 GC 回收。
示例代码
public class MyClass
{
private LuaFunction _luaFunction;
private int _luaRef;
public void SetLuaFunction(LuaFunction luaFunction)
{
_luaFunction = luaFunction;
_luaRef = luaFunction.GetReference();
}
public void CallLuaFunction()
{
if (_luaRef != 0)
{
LuaAPI.lua_getref(luaEnv.L, _luaRef);
if (LuaAPI.lua_pcall(luaEnv.L, 0, 0, 0) != 0)
{
Debug.LogError(LuaAPI.lua_tostring(luaEnv.L, -1));
}
}
}
~MyClass()
{
if (_luaRef != 0)
{
LuaAPI.lua_unref(luaEnv.L, _luaRef);
GC.SuppressFinalize(this);
}
}
}
2. Lua 引用 C# 对象
在Lua中引用C#对象时,C#侧会缓存入栈给Lua的对象,并返回实际索引给Lua。Lua侧使用弱表缓存这些C#对象。
2.1 引用过程
当 Lua 侧需要引用 C# 对象时,C# 侧会将对象缓存,并返回一个索引给 Lua。Lua 使用弱表(设置 __mode = “v”)缓存这个 C# 对象。只要没有其他 Lua 对象引用该 C# 对象,Lua 在 GC 时会触发原表中的 __gc 方法,通知 C# 该对象不再被 Lua 使用。
2.2 实现细节
- C# 对象入栈并返回索引给 Lua。
- Lua 在弱表中缓存该 C# 对象。
- 当 Lua 对象不再引用该 C# 对象时,Lua GC 触发 __gc 方法。
- C# 在接收到通知后,释放相应的资源,确保对象被 GC 回收。
示例代码
local weakTable = setmetatable({}, {__mode = "v"})
local myGameObject = CS.UnityEngine.GameObject("MyGameObject")
weakTable[1] = myGameObject
public class MyClass
{
private static Dictionary<int, GameObject> _objectCache = new Dictionary<int, GameObject>();
private static int _nextId = 1;
public static int AddObject(GameObject obj)
{
int id = _nextId++;
_objectCache[id] = obj;
return id;
}
public static GameObject GetObject(int id)
{
_objectCache.TryGetValue(id, out var obj);
return obj;
}
public static void RemoveObject(int id)
{
if (_objectCache.ContainsKey(id))
{
_objectCache.Remove(id);
}
}
}
3. 内存管理和 GC
3.1 避免 GC 的操作
所有避免 GC 的操作都是操作内存的,因此在进行相应操作时,务必管理好对应的 byte[] 句柄,并确保在不再需要时及时回收。
3.2 示例
确保在 C# 和 Lua 之间传递 byte[] 数据时,适当管理内存,避免内存泄漏。
示例代码
public class MemoryManager
{
public static IntPtr AllocateByteArray(byte[] data)
{
IntPtr ptr = Marshal.AllocHGlobal(data.Length);
Marshal.Copy(data, 0, ptr, data.Length);
return ptr;
}
public static void FreeByteArray(IntPtr ptr)
{
Marshal.FreeHGlobal(ptr);
}
}