"packages/KeraLua.1.0.9/lib/netcoreapp2.0/KeraLua.dll" did not exist on "fe27028de00e4dc06179c23ec5f1599295e8a134"
Unverified Commit b21a53bc authored by Vinicius Jarina's avatar Vinicius Jarina Committed by GitHub
Browse files

Fixed cleanup of Lua objects on LuaBase finalizer. (#282)

* Fixed cleanup of Lua objects on LuaBase finalizer.
parent f4866b5f
......@@ -1084,9 +1084,15 @@ namespace NLua
}
#endregion
internal void DisposeInternal(int reference)
internal void DisposeInternal(int reference, bool finalized)
{
if (_luaState != null)
if (finalized && _translator != null)
{
_translator.AddFinalizedReference(reference);
return;
}
if (_luaState != null && !finalized)
_luaState.Unref(reference);
}
......
......@@ -9,10 +9,22 @@ namespace NLua
{
private bool _disposed;
protected readonly int _Reference;
protected WeakReference<Lua> _Interpreter;
Lua _lua;
protected LuaBase(int reference)
protected bool TryGet(out Lua lua)
{
if (_lua.State == null)
{
lua = null;
return false;
}
lua = _lua;
return true;
}
protected LuaBase(int reference, Lua lua)
{
_lua = lua;
_Reference = reference;
}
......@@ -27,27 +39,29 @@ namespace NLua
GC.SuppressFinalize(this);
}
void DisposeLuaReference()
void DisposeLuaReference(bool finalized)
{
if (_Interpreter == null)
if (_lua == null)
return;
Lua lua;
if (!_Interpreter.TryGetTarget(out lua))
if (!TryGet(out lua))
return;
lua.DisposeInternal(_Reference);
lua.DisposeInternal(_Reference, finalized);
}
public virtual void Dispose(bool disposeManagedResources)
{
if (_disposed)
return;
// TODO: Remove the disposeManagedResources check
if (_Reference != 0 && disposeManagedResources)
bool finalized = !disposeManagedResources;
if (_Reference != 0)
{
DisposeLuaReference();
DisposeLuaReference(finalized);
}
_Interpreter = null;
_lua = null;
_disposed = true;
}
......@@ -58,7 +72,7 @@ namespace NLua
return false;
Lua lua;
if (!_Interpreter.TryGetTarget(out lua))
if (!TryGet(out lua))
return false;
return lua.CompareRef(reference._Reference, _Reference);
......
......@@ -10,16 +10,14 @@ namespace NLua
{
internal readonly LuaNativeFunction function;
public LuaFunction(int reference, Lua interpreter):base(reference)
public LuaFunction(int reference, Lua interpreter):base(reference, interpreter)
{
function = null;
_Interpreter = new WeakReference<Lua>(interpreter);
}
public LuaFunction(LuaNativeFunction nativeFunction, Lua interpreter):base (0)
public LuaFunction(LuaNativeFunction nativeFunction, Lua interpreter):base (0, interpreter)
{
function = nativeFunction;
_Interpreter = new WeakReference<Lua>(interpreter);
}
/*
......@@ -29,7 +27,7 @@ namespace NLua
internal object[] Call(object[] args, Type[] returnTypes)
{
Lua lua;
if (!_Interpreter.TryGetTarget(out lua))
if (!TryGet(out lua))
return null;
return lua.CallFunction(this, args, returnTypes);
......@@ -42,8 +40,9 @@ namespace NLua
public object[] Call(params object[] args)
{
Lua lua;
if (!_Interpreter.TryGetTarget(out lua))
if (!TryGet(out lua))
return null;
return lua.CallFunction(this, args);
}
......@@ -53,7 +52,7 @@ namespace NLua
internal void Push(LuaState luaState)
{
Lua lua;
if (!_Interpreter.TryGetTarget(out lua))
if (!TryGet(out lua))
return;
if (_Reference != 0)
......@@ -75,7 +74,7 @@ namespace NLua
return false;
Lua lua;
if (!_Interpreter.TryGetTarget(out lua))
if (!TryGet(out lua))
return false;
if (_Reference != 0 && l._Reference != 0)
......
......@@ -10,9 +10,8 @@ namespace NLua
{
public class LuaTable : LuaBase
{
public LuaTable(int reference, Lua interpreter):base(reference)
public LuaTable(int reference, Lua interpreter): base(reference, interpreter)
{
_Interpreter = new WeakReference<Lua>(interpreter);
}
/*
......@@ -22,14 +21,14 @@ namespace NLua
get
{
Lua lua;
if (!_Interpreter.TryGetTarget(out lua))
if (!TryGet(out lua))
return null;
return lua.GetObject(_Reference, field);
}
set
{
Lua lua;
if (!_Interpreter.TryGetTarget(out lua))
if (!TryGet(out lua))
return;
lua.SetObject(_Reference, field, value);
}
......@@ -42,7 +41,7 @@ namespace NLua
get
{
Lua lua;
if (!_Interpreter.TryGetTarget(out lua))
if (!TryGet(out lua))
return null;
return lua.GetObject(_Reference, field);
......@@ -50,7 +49,7 @@ namespace NLua
set
{
Lua lua;
if (!_Interpreter.TryGetTarget(out lua))
if (!TryGet(out lua))
return;
lua.SetObject(_Reference, field, value);
......@@ -60,7 +59,7 @@ namespace NLua
public IDictionaryEnumerator GetEnumerator()
{
Lua lua;
if (!_Interpreter.TryGetTarget(out lua))
if (!TryGet(out lua))
return null;
return lua.GetTableDict(this).GetEnumerator();
......@@ -71,7 +70,7 @@ namespace NLua
get
{
Lua lua;
if (!_Interpreter.TryGetTarget(out lua))
if (!TryGet(out lua))
return null;
return lua.GetTableDict(this).Keys;
......@@ -84,7 +83,7 @@ namespace NLua
get
{
Lua lua;
if (!_Interpreter.TryGetTarget(out lua))
if (!TryGet(out lua))
return null;
return lua.GetTableDict(this).Values;
......@@ -99,7 +98,7 @@ namespace NLua
internal object RawGet(string field)
{
Lua lua;
if (!_Interpreter.TryGetTarget(out lua))
if (!TryGet(out lua))
return null;
return lua.RawGetObject(_Reference, field);
......
......@@ -5,9 +5,8 @@ namespace NLua
{
public class LuaUserData : LuaBase
{
public LuaUserData(int reference, Lua interpreter):base(reference)
public LuaUserData(int reference, Lua interpreter):base(reference, interpreter)
{
_Interpreter = new WeakReference<Lua>(interpreter);
}
/*
......@@ -17,7 +16,7 @@ namespace NLua
get
{
Lua lua;
if (!_Interpreter.TryGetTarget(out lua))
if (!TryGet(out lua))
return null;
return lua.GetObject(_Reference, field);
......@@ -25,7 +24,7 @@ namespace NLua
set
{
Lua lua;
if (!_Interpreter.TryGetTarget(out lua))
if (!TryGet(out lua))
return;
lua.SetObject(_Reference, field, value);
......@@ -39,7 +38,7 @@ namespace NLua
get
{
Lua lua;
if (!_Interpreter.TryGetTarget(out lua))
if (!TryGet(out lua))
return null;
return lua.GetObject(_Reference, field);
......@@ -47,7 +46,7 @@ namespace NLua
set
{
Lua lua;
if (!_Interpreter.TryGetTarget(out lua))
if (!TryGet(out lua))
return;
lua.SetObject(_Reference, field, value);
......@@ -61,7 +60,7 @@ namespace NLua
public object[] Call(params object[] args)
{
Lua lua;
if (!_Interpreter.TryGetTarget(out lua))
if (!TryGet(out lua))
return null;
return lua.CallFunction(this, args);
......
......@@ -49,6 +49,9 @@ namespace NLua
readonly Dictionary<object, int> _objectsBackMap = new Dictionary<object, int>(new ReferenceComparer());
// object # to object (FIXME - it should be possible to get object address as an object #)
readonly Dictionary<int, object> _objects = new Dictionary<int, object>();
readonly Queue<int> finalizedReferences = new Queue<int>();
internal EventHandlerContainer PendingEvents = new EventHandlerContainer();
MetaFunctions metaFunctions;
List<Assembly> assemblies;
......@@ -851,6 +854,9 @@ namespace NLua
*/
internal LuaTable GetTable(LuaState luaState, int index)
{
// Before create new tables, check if there is any finalized object to clean.
CleanFinalizedReferences(luaState);
luaState.PushCopy(index);
int reference = luaState.Ref(LuaRegistry.Index);
if (reference == -1)
......@@ -863,6 +869,9 @@ namespace NLua
*/
internal LuaUserData GetUserData(LuaState luaState, int index)
{
// Before create new tables, check if there is any finalized object to clean.
CleanFinalizedReferences(luaState);
luaState.PushCopy(index);
int reference = luaState.Ref(LuaRegistry.Index);
if (reference == -1)
......@@ -875,6 +884,9 @@ namespace NLua
*/
internal LuaFunction GetFunction(LuaState luaState, int index)
{
// Before create new tables, check if there is any finalized object to clean.
CleanFinalizedReferences(luaState);
luaState.PushCopy(index);
int reference = luaState.Ref(LuaRegistry.Index);
if (reference == -1)
......@@ -1102,5 +1114,22 @@ namespace NLua
PushObject(luaState, res, "luaNet_metatable");
return 1;
}
internal void AddFinalizedReference(int reference)
{
finalizedReferences.Enqueue(reference);
}
void CleanFinalizedReferences(LuaState state)
{
if (finalizedReferences.Count == 0)
return;
while (finalizedReferences.Count != 0)
{
int reference = finalizedReferences.Dequeue();
state.Unref(LuaRegistry.Index, reference);
}
}
}
}
\ No newline at end of file
......@@ -2,8 +2,7 @@
using System.Text;
using System.Reflection;
using System.Threading;
using KeraLua;
using NLua;
using NLua.Exceptions;
......@@ -13,6 +12,9 @@ using NLuaTest.TestTypes;
using NUnit.Framework;
using Lua = NLua.Lua;
using LuaFunction = NLua.LuaFunction;
// ReSharper disable StringLiteralTypo
namespace NLuaTest
......@@ -2350,6 +2352,80 @@ namespace NLuaTest
}
}
[Test]
public static void TestUseLuaObjectAfterDisposeShouldNotCrash()
{
LuaTable table;
LuaFunction function;
using (var lua = new Lua())
{
lua.DoString("function F(a) return 2*a end");
function = lua.GetFunction("F");
table = lua.DoString("return { foo =\"Um dois tres\"}") [0] as LuaTable;
}
Assert.IsNotNull(function);
Assert.IsNotNull(table);
Assert.IsNull(table["foo"]);
var result = function.Call(2);
Assert.IsNull(result);
}
void ImplicitlyCreateATable(Lua lua)
{
var x = lua.DoString("return { foo = 1, bar = { la = 1 , la2 = 3, la4 = \"aidsjiasjdiasjdiajsdi\"} }")[0] as LuaTable;
var foo = x["foo"];
x = null;
}
void PleaseRunFinalizers()
{
for (int i = 0; i < 5; i++)
{
GC.Collect();
GC.WaitForPendingFinalizers();
Thread.Sleep(0);
}
}
///*
// * Tests if Lua objects are being released on finalizer
// */
[Test]
public void TestTableFinalizerDispose()
{
using (Lua lua = new Lua())
{
int before = lua.State.GarbageCollector(LuaGC.Count, 0);
for (int i = 0; i < 1000; i++)
ImplicitlyCreateATable(lua);
int after1 = lua.State.GarbageCollector(LuaGC.Count, 0);
PleaseRunFinalizers();
ImplicitlyCreateATable(lua);
lua.State.GarbageCollector(LuaGC.Collect, 0);
int after2 = lua.State.GarbageCollector(LuaGC.Count, 0);
int ratio = after2 / before;
int ratio2 = after1 / after2;
// The ratio two is very uncertain, lets use 5x, just to have some certain that
// the gc collect the tables
Assert.True( ratio2 >= 5 , "#1:" + ratio2);
Assert.True( ratio <= 1, "#2:" + ratio);
}
}
static Lua m_lua;
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment