从C中回调闭包时,在垃圾回收中发生了MemFault。

我正在使用 Keil、MDK-ARM Pro 4.71 为 Cortex-M3 目标(STM32F107)工作。

我已经编译了 Lua 解释器和一个 Lua"计时器"模块,它与芯片的定时器接口。当计时器过期时,我想调用一个 lua 函数。

以下是样例:

t = timer.open()
t.event = function() print("Bing !") end
t:start()

到目前为止,一切正常:-)!每次计时器过期时,我都会看到打印"Bing !"的消息。

现在,如果我使用一个闭包:

t = timer.open()
i = 0
t.event = function() i = i + 1; print(i); end
t:start()

在一些计时器更新后,我会在 GC 中遇到糟糕的内存访问。由于它是一个内嵌的上下文,有非常少的内存,如果存在泄漏,我可能会很快用完内存。

这是"t.event"设置器(ELIB \ _TIMER 是一个表示我的计时器的 C 结构):

static int ElibTimerSetEvent(lua_State* L)
{
   ELIB_TIMER* pTimer_X = ElibCheckTimer(L, 1, TRUE);

   if (pTimer_X->LuaFuncKey_i != LUA_REFNIL)
   {
      luaL_unref(L, LUA_REGISTRYINDEX, pTimer_X->LuaFuncKey_i);
      pTimer_X->LuaFuncKey_i = LUA_REFNIL;
   }

   if (!lua_isnil(L, 2))
   {
      pTimer_X->LuaFuncKey_i = luaL_ref(L, LUA_REGISTRYINDEX);
   }

   return 0;
}

这是本地回调实现:

static void ElibTimerEventHandler(SYSEVT_HANDLE Event_H)
{
   ELIB_TIMER* pTimer_X = (ELIB_TIMER*)SWLIB_SYSEVT_GetSideData(Event_H);
   lua_State* L = pTimer_X->L;
   int i = lua_gettop(L);
   if (pTimer_X->LuaFuncKey_i != LUA_REFNIL)
   {
      lua_rawgeti(L, LUA_REGISTRYINDEX, pTimer_X->LuaFuncKey_i);
      lua_call(L, 0, 0);
      lua_settop(L, i);
   }
}

这是在外部同步的,所以这不是同步问题。

我做错了什么吗?

编辑

这是调用栈(使用 lua \ _pcall 而不是 lua \ _call,但它是相同的)。第一行是我硬故障处理程序的。

Lua call stack

点赞
用户1251821
用户1251821

发现你的 C 代码中有一个 bug。你在 static int ElibTimerSetEvent(lua_State* L) 中打破了 lua 堆栈。

luaL_ref 会弹出 Lua 堆栈顶部的值:http://www.lua.org/manual/5.2/manual.html#luaL_ref

所以在调用 luaL_ref 之前,你需要将被引用的值复制一份:

lua_pushvalue(L, 2); // 将回调函数推入栈顶,然后由 luaL_ref() 使用

请修复这个问题并重试。

2013-08-20 03:25:22
用户254057
用户254057

我解决了问题!我已经用尽了堆栈(原生堆栈,而不是Lua堆栈)空间 :p。

我猜测这个特定的脚本引起了一个非常长的调用堆栈。在增加分配给原生堆栈的内存之后,问题消失了。相反,如果我减少它,我甚至无法初始化解释器。

非常感谢在这里尝试帮助的人们。

2013-08-20 06:59:15