From ed9b7b3eb1633fb921b1763e1f87533d96dfeb5c Mon Sep 17 00:00:00 2001 From: adelikat Date: Sun, 12 Jul 2020 15:48:45 -0500 Subject: [PATCH] Lua address several memory leaks - when a script stops, take any registered functions and spawn new threads for them to execute, and regularly dispose them. Also, the main lua thread needs to have scheduled disposes run on it, even if there is no active scripts (it was being run as part of disposing individual scripts, needs refactoring). All of this fixes #1920 --- .../lua/NamedLuaFunction.cs | 21 ++++++++++++------- .../tools/Lua/LuaConsole.cs | 17 +++++++++++++++ .../tools/Lua/LuaLibraries.cs | 2 ++ .../tools/Lua/UnixLuaLibraries.cs | 4 ++++ .../tools/Lua/Win32LuaLibraries.cs | 4 +++- 5 files changed, 39 insertions(+), 9 deletions(-) diff --git a/src/BizHawk.Client.Common/lua/NamedLuaFunction.cs b/src/BizHawk.Client.Common/lua/NamedLuaFunction.cs index 089e9949cc..1d0bccc32d 100644 --- a/src/BizHawk.Client.Common/lua/NamedLuaFunction.cs +++ b/src/BizHawk.Client.Common/lua/NamedLuaFunction.cs @@ -23,13 +23,7 @@ namespace BizHawk.Client.Common // and we should refactor if (luaFile == null) { - var thread = new Lua(); - - // Current dir will have to do for now, but this will inevitably not be desired - // Users will expect it to be the same directly as the thread that spawned this callback - // But how do we know what that directory was? - LuaSandbox.CreateSandbox(thread, "."); - LuaFile = new LuaFile(".") { Thread = thread }; + DetachFromScript(); } else { @@ -53,11 +47,22 @@ namespace BizHawk.Client.Common MemCallback = (address, value, flags) => Callback(); } + public void DetachFromScript() + { + var thread = new Lua(); + + // Current dir will have to do for now, but this will inevitably not be desired + // Users will expect it to be the same directly as the thread that spawned this callback + // But how do we know what that directory was? + LuaSandbox.CreateSandbox(thread, "."); + LuaFile = new LuaFile(".") { Thread = thread }; + } + public Guid Guid { get; } public string Name { get; } - public LuaFile LuaFile { get; } + public LuaFile LuaFile { get; private set; } public string Event { get; } diff --git a/src/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs b/src/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs index 349c8f2f87..1155b275d0 100644 --- a/src/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs +++ b/src/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs @@ -635,6 +635,7 @@ namespace BizHawk.Client.EmuHawk if (!prohibit) { var result = LuaImp.ResumeScript(lf); + DetachRegisteredFunctions(lf); if (result.Terminated) { LuaImp.CallExitEvent(lf); @@ -647,6 +648,7 @@ namespace BizHawk.Client.EmuHawk }, () => { lf.Stop(); + DetachRegisteredFunctions(lf); LuaListView.Refresh(); }); } @@ -656,9 +658,24 @@ namespace BizHawk.Client.EmuHawk } } + LuaImp.RunScheduledDisposes(); + foreach (var nlf in LuaImp.RegisteredFunctions) + { + nlf.LuaFile.Thread.RunScheduledDisposes(); + } + _messageCount = 0; } + private void DetachRegisteredFunctions(LuaFile lf) + { + foreach (var nlf in LuaImp.RegisteredFunctions + .Where(f => f.LuaFile == lf)) + { + nlf.DetachFromScript(); + } + } + private FileInfo GetSaveFileFromUser() { var sfd = new SaveFileDialog(); diff --git a/src/BizHawk.Client.EmuHawk/tools/Lua/LuaLibraries.cs b/src/BizHawk.Client.EmuHawk/tools/Lua/LuaLibraries.cs index 4f13afdcaa..03c79b7fd4 100644 --- a/src/BizHawk.Client.EmuHawk/tools/Lua/LuaLibraries.cs +++ b/src/BizHawk.Client.EmuHawk/tools/Lua/LuaLibraries.cs @@ -34,5 +34,7 @@ namespace BizHawk.Client.EmuHawk public abstract void SpawnAndSetFileThread(string pathToLoad, LuaFile lf); public abstract void StartLuaDrawing(); public abstract void WindowClosed(IntPtr handle); + + public abstract void RunScheduledDisposes(); } } \ No newline at end of file diff --git a/src/BizHawk.Client.EmuHawk/tools/Lua/UnixLuaLibraries.cs b/src/BizHawk.Client.EmuHawk/tools/Lua/UnixLuaLibraries.cs index ef7b7d8561..d9b3542422 100644 --- a/src/BizHawk.Client.EmuHawk/tools/Lua/UnixLuaLibraries.cs +++ b/src/BizHawk.Client.EmuHawk/tools/Lua/UnixLuaLibraries.cs @@ -54,5 +54,9 @@ namespace BizHawk.Client.EmuHawk public override void WindowClosed(IntPtr handle) { } + + public override void RunScheduledDisposes() + { + } } } \ No newline at end of file diff --git a/src/BizHawk.Client.EmuHawk/tools/Lua/Win32LuaLibraries.cs b/src/BizHawk.Client.EmuHawk/tools/Lua/Win32LuaLibraries.cs index fdc0fffde2..5e3a28d03d 100644 --- a/src/BizHawk.Client.EmuHawk/tools/Lua/Win32LuaLibraries.cs +++ b/src/BizHawk.Client.EmuHawk/tools/Lua/Win32LuaLibraries.cs @@ -192,6 +192,8 @@ namespace BizHawk.Client.EmuHawk _lua.Pop(); } + public override void RunScheduledDisposes() => _lua.RunScheduledDisposes(); + public override ResumeResult ResumeScript(LuaFile lf) { _currThread = lf.Thread; @@ -202,7 +204,7 @@ namespace BizHawk.Client.EmuHawk var execResult = _currThread.Resume(0); - _lua.RunScheduledDisposes(); + _lua.RunScheduledDisposes(); // TODO: I don't think this is needed anymore, we run this regularly anyway // not sure how this is going to work out, so do this too _currThread.RunScheduledDisposes();