From df1b76f3afd077a390997ace0a9abb5ff1b61d81 Mon Sep 17 00:00:00 2001 From: ElPsyCongree <345036769@qq.com> Date: Thu, 14 Jun 2018 18:25:36 +0800 Subject: [PATCH] fix lua_tostring gc --- Assets/Plugins/Slua_Managed/LuaDLL.cs | 278 ++++++++++-------- Assets/Plugins/Slua_Managed/LuaState.cs | 84 +++++- Assets/Plugins/Slua_Managed/WeakDictionary.cs | 24 +- Assets/Slua/Resources/circle/circle.txt | 6 +- 4 files changed, 259 insertions(+), 133 deletions(-) diff --git a/Assets/Plugins/Slua_Managed/LuaDLL.cs b/Assets/Plugins/Slua_Managed/LuaDLL.cs index f4a7d4ed..cb0e1993 100644 --- a/Assets/Plugins/Slua_Managed/LuaDLL.cs +++ b/Assets/Plugins/Slua_Managed/LuaDLL.cs @@ -73,9 +73,9 @@ public enum LuaThreadStatus : int public sealed class LuaIndexes { -#if LUA_5_3 - // for lua5.3 - public static int LUA_REGISTRYINDEX = -1000000 - 1000; +#if LUA_5_3 + // for lua5.3 + public static int LUA_REGISTRYINDEX = -1000000 - 1000; #else // for lua5.1 or luajit public static int LUA_REGISTRYINDEX = -10000; @@ -93,8 +93,8 @@ public struct ReaderInfo #if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate int LuaCSFunction(IntPtr luaState); -#else - public delegate int LuaCSFunction(IntPtr luaState); +#else + public delegate int LuaCSFunction(IntPtr luaState); #endif public delegate string LuaChunkReader(IntPtr luaState, ref ReaderInfo data, ref uint size); @@ -102,9 +102,10 @@ public struct ReaderInfo public delegate int LuaFunctionCallback(IntPtr luaState); public class LuaDLL { + public const int SHORT_STRING_MAX_LEN = 250; public static int LUA_MULTRET = -1; -#if UNITY_IPHONE && !UNITY_EDITOR - const string LUADLL = "__Internal"; +#if UNITY_IPHONE && !UNITY_EDITOR + const string LUADLL = "__Internal"; #else const string LUADLL = "slua"; #endif @@ -224,126 +225,126 @@ public static void lua_newtable(IntPtr luaState) LuaDLL.lua_createtable(luaState, 0, 0); } -#if LUA_5_3 - [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)] - public static extern void lua_getglobal(IntPtr luaState, string name); - - [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)] - public static extern void lua_setglobal(IntPtr luaState, string name); - - public static void lua_insert(IntPtr luaState, int newTop) - { - lua_rotate(luaState, newTop, 1); - } - - public static void lua_pushglobaltable(IntPtr l) - { - lua_rawgeti(l, LuaIndexes.LUA_REGISTRYINDEX, 2); - } - - [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)] - public static extern int lua_rotate(IntPtr luaState, int index, int n); - - public static int lua_rawlen(IntPtr luaState, int stackPos) - { - return LuaDLLWrapper.luaS_rawlen(luaState, stackPos); - } - - [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)] - public static extern int luaL_loadbufferx(IntPtr luaState, byte[] buff, int size, string name, IntPtr x); - - [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)] - public static extern int lua_callk(IntPtr luaState, int nArgs, int nResults,int ctx,IntPtr k); - - [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)] - public static extern int lua_pcallk(IntPtr luaState, int nArgs, int nResults, int errfunc,int ctx,IntPtr k); - -// [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)] -// public static extern int luaS_pcall(IntPtr luaState, int nArgs, int nResults, int errfunc); - - public static int lua_call(IntPtr luaState, int nArgs, int nResults) - { - return lua_callk(luaState, nArgs, nResults, 0, IntPtr.Zero); - } - - public static int lua_pcall(IntPtr luaState, int nArgs, int nResults, int errfunc) - { - return lua_pcallk(luaState, nArgs, nResults, errfunc, 0, IntPtr.Zero); - } - - [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)] - public static extern double lua_tonumberx(IntPtr luaState, int index, IntPtr x); - public static double lua_tonumber(IntPtr luaState, int index) - { - return lua_tonumberx(luaState, index, IntPtr.Zero); - } - [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)] - public static extern Int64 lua_tointegerx(IntPtr luaState, int index,IntPtr x); - public static int lua_tointeger(IntPtr luaState, int index) - { - return (int)lua_tointegerx(luaState, index, IntPtr.Zero); - } - - - public static int luaL_loadbuffer(IntPtr luaState, byte[] buff, int size, string name) - { - return luaL_loadbufferx(luaState, buff, size, name, IntPtr.Zero); - } - - public static void lua_remove(IntPtr l, int idx) - { - lua_rotate(l, (idx), -1); - lua_pop(l, 1); - } - - [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)] - public static extern void lua_rawgeti(IntPtr luaState, int tableIndex, Int64 index); - - [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)] - public static extern void lua_rawseti(IntPtr luaState, int tableIndex, Int64 index); - - [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)] - public static extern void lua_pushinteger(IntPtr luaState, Int64 i); - - public static Int64 luaL_checkinteger(IntPtr luaState, int stackPos) { - luaL_checktype(luaState, stackPos, LuaTypes.LUA_TNUMBER); - return lua_tointegerx(luaState, stackPos, IntPtr.Zero); - } - - [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)] - public static extern int luaS_yield(IntPtr luaState,int nrets); - - public static int lua_yield(IntPtr luaState,int nrets) { - return luaS_yield(luaState,nrets); - } - - - [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)] - public static extern int lua_resume(IntPtr L, IntPtr from, int narg); +#if LUA_5_3 + [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)] + public static extern void lua_getglobal(IntPtr luaState, string name); + + [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)] + public static extern void lua_setglobal(IntPtr luaState, string name); + + public static void lua_insert(IntPtr luaState, int newTop) + { + lua_rotate(luaState, newTop, 1); + } + + public static void lua_pushglobaltable(IntPtr l) + { + lua_rawgeti(l, LuaIndexes.LUA_REGISTRYINDEX, 2); + } + + [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)] + public static extern int lua_rotate(IntPtr luaState, int index, int n); + + public static int lua_rawlen(IntPtr luaState, int stackPos) + { + return LuaDLLWrapper.luaS_rawlen(luaState, stackPos); + } + + [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)] + public static extern int luaL_loadbufferx(IntPtr luaState, byte[] buff, int size, string name, IntPtr x); + + [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)] + public static extern int lua_callk(IntPtr luaState, int nArgs, int nResults,int ctx,IntPtr k); + + [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)] + public static extern int lua_pcallk(IntPtr luaState, int nArgs, int nResults, int errfunc,int ctx,IntPtr k); + +// [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)] +// public static extern int luaS_pcall(IntPtr luaState, int nArgs, int nResults, int errfunc); + + public static int lua_call(IntPtr luaState, int nArgs, int nResults) + { + return lua_callk(luaState, nArgs, nResults, 0, IntPtr.Zero); + } + + public static int lua_pcall(IntPtr luaState, int nArgs, int nResults, int errfunc) + { + return lua_pcallk(luaState, nArgs, nResults, errfunc, 0, IntPtr.Zero); + } + + [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)] + public static extern double lua_tonumberx(IntPtr luaState, int index, IntPtr x); + public static double lua_tonumber(IntPtr luaState, int index) + { + return lua_tonumberx(luaState, index, IntPtr.Zero); + } + [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)] + public static extern Int64 lua_tointegerx(IntPtr luaState, int index,IntPtr x); + public static int lua_tointeger(IntPtr luaState, int index) + { + return (int)lua_tointegerx(luaState, index, IntPtr.Zero); + } + + + public static int luaL_loadbuffer(IntPtr luaState, byte[] buff, int size, string name) + { + return luaL_loadbufferx(luaState, buff, size, name, IntPtr.Zero); + } + + public static void lua_remove(IntPtr l, int idx) + { + lua_rotate(l, (idx), -1); + lua_pop(l, 1); + } + + [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)] + public static extern void lua_rawgeti(IntPtr luaState, int tableIndex, Int64 index); + + [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)] + public static extern void lua_rawseti(IntPtr luaState, int tableIndex, Int64 index); + + [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)] + public static extern void lua_pushinteger(IntPtr luaState, Int64 i); + + public static Int64 luaL_checkinteger(IntPtr luaState, int stackPos) { + luaL_checktype(luaState, stackPos, LuaTypes.LUA_TNUMBER); + return lua_tointegerx(luaState, stackPos, IntPtr.Zero); + } + + [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)] + public static extern int luaS_yield(IntPtr luaState,int nrets); + + public static int lua_yield(IntPtr luaState,int nrets) { + return luaS_yield(luaState,nrets); + } + + + [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)] + public static extern int lua_resume(IntPtr L, IntPtr from, int narg); public static int lua_resume(IntPtr L, int narg) { return lua_resume(L, IntPtr.Zero, narg); } - - public static void lua_replace(IntPtr luaState, int index) { - lua_copy(luaState, -1, (index)); - lua_pop(luaState, 1); - } - - [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)] - public static extern void lua_copy(IntPtr luaState,int from,int toidx); - - [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)] - public static extern int lua_isinteger(IntPtr luaState, int p); - - [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)] - public static extern int lua_compare(IntPtr luaState, int index1, int index2, int op); - - public static int lua_equal(IntPtr luaState, int index1, int index2) - { - return lua_compare(luaState, index1, index2, 0); - } - + + public static void lua_replace(IntPtr luaState, int index) { + lua_copy(luaState, -1, (index)); + lua_pop(luaState, 1); + } + + [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)] + public static extern void lua_copy(IntPtr luaState,int from,int toidx); + + [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)] + public static extern int lua_isinteger(IntPtr luaState, int p); + + [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)] + public static extern int lua_compare(IntPtr luaState, int index1, int index2, int op); + + public static int lua_equal(IntPtr luaState, int index1, int index2) + { + return lua_compare(luaState, index1, index2, 0); + } + #else [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)] public static extern int lua_resume(IntPtr L, int narg); @@ -458,9 +459,9 @@ public static void lua_pop(IntPtr luaState, int amount) [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)] public static extern void lua_rawset(IntPtr luaState, int index); -#if LUA_5_3 - [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)] - public static extern void lua_setmetatable(IntPtr luaState, int objIndex); +#if LUA_5_3 + [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)] + public static extern void lua_setmetatable(IntPtr luaState, int objIndex); #else [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)] public static extern int lua_setmetatable(IntPtr luaState, int objIndex); @@ -554,18 +555,37 @@ public static string lua_tostring(IntPtr luaState, int index) { int strlen; + /* + * LUA jit 思路 先把lua的字符串 ref起来,这样lua的GC就无法 释放这个字符串 + * 然后c#这边写一个LuaString类以及一个lua字符串指针地址为key的weak字典 + * 因为c#这边该字符串只有weak字典中有引用关系,所以c#会自动 清理这些LuaString + * 最后利用LuaString的析构函数来清理lua的ref,这样该字符串的luaGC就可以生效了 + * 总之 只要保证,c#字符串 缓存字典中的索引lua那边没有GC掉这个字符串就好办 + * TODO lua5.3 可能直接 把短字符串全部 缓存起来(因为5.3 短字符并不参与GC,所以指针地址并不会发生改变) + */ + IntPtr str = luaS_tolstring32(luaState, index, out strlen); // fix il2cpp 64 bit + LuaState state = LuaState.get(luaState); string s = null; if (strlen > 0 && str != IntPtr.Zero) { + //Lua 5.3 版本短字符串(长度40)会 缓存到intern里面,相应处理一下 + if (strlen <= SHORT_STRING_MAX_LEN && state.TryGetLuaString(str, out s)) + { + return s; + } s = Marshal.PtrToStringAnsi(str); // fallback method - if(s == null) + if (s == null) { byte[] b = new byte[strlen]; Marshal.Copy(str, b, 0, strlen); s = System.Text.Encoding.Default.GetString(b); } + if (strlen <= SHORT_STRING_MAX_LEN) + { + state.refString(str, index, s); + } } return (s == null) ? string.Empty : s; } @@ -668,8 +688,8 @@ public static int lua_absindex(IntPtr luaState, int index) public static int lua_upvalueindex(int i) { -#if LUA_5_3 - return LuaIndexes.LUA_REGISTRYINDEX - i; +#if LUA_5_3 + return LuaIndexes.LUA_REGISTRYINDEX - i; #else return LuaIndexes.LUA_GLOBALSINDEX - i; #endif diff --git a/Assets/Plugins/Slua_Managed/LuaState.cs b/Assets/Plugins/Slua_Managed/LuaState.cs index 6a6f5293..4309828c 100644 --- a/Assets/Plugins/Slua_Managed/LuaState.cs +++ b/Assets/Plugins/Slua_Managed/LuaState.cs @@ -434,6 +434,33 @@ IEnumerator IEnumerable.GetEnumerator() } } + public class LuaString : LuaVar + { + public string value { get; set; } + public IntPtr strPoint { get; set; } + public LuaString(IntPtr l, IntPtr sp, int valueRef, string s) + { + state = LuaState.get(l); + strPoint = sp; + valueref = valueRef; + value = s; + } + + ~LuaString() + { + Dispose(false); + } + + public override void Dispose(bool disposeManagedResources) + { + if (valueref != 0) + { + state.gcRefLuaString(strPoint, valueref); + strPoint = IntPtr.Zero; + valueref = 0; + } + } + } @@ -442,9 +469,11 @@ public class LuaState : IDisposable { IntPtr l_; int mainThread = 0; + const int MAX_WEAK_STRING = 1000; internal WeakDictionary delgateMap = new WeakDictionary(); + internal WeakDictionary weakStringTb = new WeakDictionary(MAX_WEAK_STRING); - public int cachedDelegateCount{ + public int cachedDelegateCount{ get{ return this.delgateMap.AliveCount; } @@ -710,6 +739,59 @@ local function index(ud,k) createGameObject(); } + #region lua string cache + public bool TryGetLuaString(IntPtr p, out string result) + { + LuaString ls; + + bool ret = weakStringTb.TryGetValue((long)p, out ls); + if (ret) + { + result = ls.value; + } + else + { + result = string.Empty; + } + return ret; + } + + // ref鎺塩#鐨勫瓧绗︿覆 + public void refString(IntPtr strPoint, int index, string s) + { + lock (this) + { + //瓒呰繃缂撳瓨涓婇檺灏辩瓑鐫 閲婃斁鍚 + if (weakStringTb.Count >= MAX_WEAK_STRING) + { + return; + } + int oldTop = LuaDLL.lua_gettop(l_); + LuaDLL.lua_pushvalue(l_, index); + int refIndex = LuaDLL.luaL_ref(l_, LuaIndexes.LUA_REGISTRYINDEX); + LuaDLL.lua_settop(l_, oldTop); + + LuaString ls = new LuaString(l_, strPoint, refIndex, s); + + weakStringTb[(long)strPoint] = ls; + } + } + private static void gcStringAction(IntPtr l, int r) + { + LuaDLL.lua_unref(l, r); + } + //閲婃斁鎺 + public void gcRefLuaString(IntPtr strPoint, int refIndex) + { + //杩欑帺鎰 鏋愭瀯 鍑芥暟璋冪敤杩囨潵锛屽鏄撻潪鍚屼竴绾跨▼锛宭ock浣忕ǔ + lock (this) + { + weakStringTb.Remove((long)strPoint); + gcRef(gcStringAction, refIndex); + } + } + #endregion + void createGameObject() { #if !SLUA_STANDALONE diff --git a/Assets/Plugins/Slua_Managed/WeakDictionary.cs b/Assets/Plugins/Slua_Managed/WeakDictionary.cs index 02f1f1d2..c8f9fed2 100644 --- a/Assets/Plugins/Slua_Managed/WeakDictionary.cs +++ b/Assets/Plugins/Slua_Managed/WeakDictionary.cs @@ -29,9 +29,29 @@ namespace SLua public class WeakDictionary { - Dictionary _dict = new Dictionary(); + readonly Dictionary _dict = new Dictionary(); + public WeakDictionary() + { + _dict = new Dictionary(); + } - public V this[K key] + public WeakDictionary(int capacity) + { + _dict = new Dictionary(capacity); + } + public int Count + { + get + { + return _dict.Count; + } + } + public void Clear() + { + _dict.Clear(); + } + + public V this[K key] { get { diff --git a/Assets/Slua/Resources/circle/circle.txt b/Assets/Slua/Resources/circle/circle.txt index 7bb5b20d..bd2b0470 100644 --- a/Assets/Slua/Resources/circle/circle.txt +++ b/Assets/Slua/Resources/circle/circle.txt @@ -61,8 +61,8 @@ function class:init(count) end end +local value = 0 function class:update() -- gc alloc is zero - for i,v in ipairs(self.cubes) do local offset = i%2==1 and 5 or -5 local r = self.r+math.sin(Time.time)*offset @@ -72,6 +72,9 @@ function class:update() -- gc alloc is zero v[1].transform.position = base --v[2].color=self.colors[math.random(#self.colors)] + + --姝ゅc#閭h竟浼氫笉鍋 tostring + v[1].transform.name = tostring(value) end if not self.fogStart or self.t>1 then @@ -87,6 +90,7 @@ function class:update() -- gc alloc is zero self.f=self.f+1 self.framet=self.framet+Time.deltaTime if self.framet>=1 then + value = value + 1 self.ftext.text=string.format("fps:%d",self.f) self.f=0 self.framet=self.framet-1