Merge branch 'unloadedcontainers' into 'master'

Fix Lua memory usage

See merge request OpenMW/openmw!4363
This commit is contained in:
Petr Mikheev 2024-10-15 21:18:13 +00:00
commit bac0018a09
10 changed files with 425 additions and 97 deletions

View file

@ -6,6 +6,7 @@
#include <components/lua/asyncpackage.hpp>
#include <components/lua/luastate.hpp>
#include <components/lua/scriptscontainer.hpp>
#include <components/lua/scripttracker.hpp>
#include <components/testing/util.hpp>
@ -135,6 +136,31 @@ return {
end,
},
}
)X");
constexpr VFS::Path::NormalizedView unloadPath("unload.lua");
VFSTestFile unloadScript(R"X(
x = 0
y = 0
z = 0
return {
engineHandlers = {
onSave = function(state)
print('saving', x, y, z)
return {x = x, y = y}
end,
onLoad = function(state)
x, y = state.x, state.y
print('loaded', x, y, z)
end
},
eventHandlers = {
Set = function(eventData)
x, y, z = eventData.x, eventData.y, eventData.z
end
}
}
)X");
struct LuaScriptsContainerTest : Test
@ -151,6 +177,7 @@ return {
{ testInterfacePath, &interfaceScript },
{ overrideInterfacePath, &overrideInterfaceScript },
{ useInterfacePath, &useInterfaceScript },
{ unloadPath, &unloadScript },
});
LuaUtil::ScriptsConfiguration mCfg;
@ -171,6 +198,7 @@ CUSTOM, NPC: loadSave2.lua
CUSTOM, PLAYER: testInterface.lua
CUSTOM, PLAYER: overrideInterface.lua
CUSTOM, PLAYER: useInterface.lua
CUSTOM: unload.lua
)X");
mCfg.init(std::move(cfg));
}
@ -511,4 +539,35 @@ CUSTOM, PLAYER: useInterface.lua
Log::sMinDebugLevel = level;
}
TEST_F(LuaScriptsContainerTest, Unload)
{
LuaUtil::ScriptTracker tracker;
LuaUtil::ScriptsContainer scripts1(&mLua, "Test", &tracker, false);
EXPECT_TRUE(scripts1.addCustomScript(*mCfg.findId(unloadPath)));
EXPECT_EQ(tracker.size(), 1);
mLua.protectedCall([&](LuaUtil::LuaView& lua) {
scripts1.receiveEvent("Set", LuaUtil::serialize(lua.sol().create_table_with("x", 3, "y", 2, "z", 1)));
testing::internal::CaptureStdout();
for (int i = 0; i < 600; ++i)
tracker.unloadInactiveScripts(lua);
EXPECT_EQ(tracker.size(), 0);
scripts1.receiveEvent("Set", LuaUtil::serialize(lua.sol().create_table_with("x", 10, "y", 20, "z", 30)));
EXPECT_EQ(internal::GetCapturedStdout(),
"Test[unload.lua]:\tsaving\t3\t2\t1\n"
"Test[unload.lua]:\tloaded\t3\t2\t0\n");
});
EXPECT_EQ(tracker.size(), 1);
ESM::LuaScripts data;
scripts1.save(data);
EXPECT_EQ(tracker.size(), 1);
mLua.protectedCall([&](LuaUtil::LuaView& lua) {
for (int i = 0; i < 600; ++i)
tracker.unloadInactiveScripts(lua);
});
EXPECT_EQ(tracker.size(), 0);
scripts1.load(data);
EXPECT_EQ(tracker.size(), 0);
}
}

View file

@ -224,8 +224,8 @@ namespace MWLua
};
}
LocalScripts::LocalScripts(LuaUtil::LuaState* lua, const LObject& obj)
: LuaUtil::ScriptsContainer(lua, "L" + obj.id().toString())
LocalScripts::LocalScripts(LuaUtil::LuaState* lua, const LObject& obj, LuaUtil::ScriptTracker* tracker)
: LuaUtil::ScriptsContainer(lua, "L" + obj.id().toString(), tracker, false)
, mData(obj)
{
lua->protectedCall(

View file

@ -62,12 +62,13 @@ namespace MWLua
{
public:
static void initializeSelfPackage(const Context&);
LocalScripts(LuaUtil::LuaState* lua, const LObject& obj);
LocalScripts(LuaUtil::LuaState* lua, const LObject& obj, LuaUtil::ScriptTracker* tracker = nullptr);
MWBase::LuaManager::ActorControls* getActorControls() { return &mData.mControls; }
const MWWorld::Ptr& getPtrOrEmpty() const { return mData.ptrOrEmpty(); }
void setActive(bool active);
bool isActive() const override { return mData.mIsActive; }
void onConsume(const LObject& consumable) { callEngineHandlers(mOnConsumeHandlers, consumable); }
void onActivated(const LObject& actor) { callEngineHandlers(mOnActivatedHandlers, actor); }
void onTeleported() { callEngineHandlers(mOnTeleportedHandlers); }

View file

@ -210,6 +210,8 @@ namespace MWLua
scripts->update(frameDuration);
mGlobalScripts.update(frameDuration);
}
mLua.protectedCall([&](LuaUtil::LuaView& lua) { mScriptTracker.unloadInactiveScripts(lua); });
}
void LuaManager::objectTeleported(const MWWorld::Ptr& ptr)
@ -560,7 +562,7 @@ namespace MWLua
}
else
{
scripts = std::make_shared<LocalScripts>(&mLua, LObject(getId(ptr)));
scripts = std::make_shared<LocalScripts>(&mLua, LObject(getId(ptr)), &mScriptTracker);
if (!autoStartConf.has_value())
autoStartConf = mConfiguration.getLocalConf(type, ptr.getCellRef().getRefId(), getId(ptr));
scripts->setAutoStartConf(std::move(*autoStartConf));

View file

@ -8,6 +8,7 @@
#include <components/lua/inputactions.hpp>
#include <components/lua/luastate.hpp>
#include <components/lua/scripttracker.hpp>
#include <components/lua/storage.hpp>
#include <components/lua_ui/resources.hpp>
#include <components/misc/color.hpp>
@ -234,6 +235,8 @@ namespace MWLua
LuaUtil::InputAction::Registry mInputActions;
LuaUtil::InputTrigger::Registry mInputTriggers;
LuaUtil::ScriptTracker mScriptTracker;
};
}