You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将Raylib的GetMousePosition()绑定到Lua引发内存泄漏[Lua C API]

问题:Lua绑定GetMousePosition时频繁创建表导致内存波动

我通过Lua C API实现了lua_getmouseposition函数,绑定Raylib的GetMousePosition()获取鼠标位置,将结果存入Vector2后转成Lua表返回。但Lua脚本循环调用时,每次都会生成新表,内存每秒涨45-95KB,GC回收后又快速回升,频繁触发GC。试过lua_pop和MemFree()没用,其他Raylib函数绑定正常,求修改方案,避免频繁创建新表。

绑定函数原代码:

static int lua_getmouseposition(lua_State *L) {

Vector2 *mousePosition = MemAlloc(sizeof(Vector2));

if (mousePosition == NULL) {
    MemFree(mousePosition);
    return luaL_error(L, " GetMousePos error: out of memory \n");
}

*mousePosition = GetMousePosition();

lua_newtable(L);
// push x value to the table
lua_pushstring(L, "x");
lua_pushnumber(L, mousePosition->x);
lua_settable(L, -3);

// push y value to the table
lua_pushstring(L, "y");
lua_pushnumber(L, mousePosition->y);
lua_settable(L, -3);

lua_pop(L, -3);

MemFree(mousePosition);

return 1;
}

Lua脚本原代码:

while not WinShouldClose() do
begin()
    cls(0, 0, 0) -- clear the screen, with a certain color
    
    pos = GetMousePos()
    
    -- draw the player (rectangle/square)
    DrawImage(sprite, pos1.x, pos1.y)
    
    playerInput()

    displayInfo()
    
stop()
end

解决方案

方案1:复用全局缓存表

在Lua全局环境中维护一个固定的鼠标位置表,每次调用仅更新表内的x、y值,彻底避免频繁创建新表。

修改后的C代码:

static int lua_getmouseposition(lua_State *L) {
    // 尝试获取全局环境中的缓存表
    lua_getglobal(L, "__mouse_pos_cache");
    if (!lua_istable(L, -1)) {
        lua_pop(L, 1); // 弹出栈上的非表值
        lua_newtable(L);
        lua_pushvalue(L, -1);
        lua_setglobal(L, "__mouse_pos_cache"); // 将新表存入全局环境
    }

    // 直接用栈上变量存储鼠标位置,无需动态分配
    Vector2 mousePosition = GetMousePosition();

    // 更新表内的x、y值
    lua_pushstring(L, "x");
    lua_pushnumber(L, mousePosition.x);
    lua_settable(L, -3);

    lua_pushstring(L, "y");
    lua_pushnumber(L, mousePosition.y);
    lua_settable(L, -3);

    // 返回复用的缓存表
    return 1;
}

方案2:让Lua脚本传入表复用

如果不想依赖全局表,可让Lua脚本提前创建表并传入函数,函数仅更新该表的内容。

修改后的C代码:

static int lua_getmouseposition(lua_State *L) {
    // 检查是否传入了表参数,无参数则创建新表(兼容原有调用逻辑)
    int create_new = 0;
    if (!lua_istable(L, 1)) {
        lua_newtable(L);
        create_new = 1;
    } else {
        lua_pushvalue(L, 1); // 将传入的表推到栈顶
    }

    Vector2 mousePosition = GetMousePosition();

    // 更新表内容
    lua_pushstring(L, "x");
    lua_pushnumber(L, mousePosition.x);
    lua_settable(L, -3);

    lua_pushstring(L, "y");
    lua_pushnumber(L, mousePosition.y);
    lua_settable(L, -3);

    // 返回表(新创建/传入的表)
    return 1;
}

对应的Lua脚本修改:

-- 提前创建一次表,后续循环复用
local pos = {}
while not WinShouldClose() do
begin()
    cls(0, 0, 0)
    
    GetMousePos(pos) -- 传入已有表更新内容
    
    DrawImage(sprite, pos.x, pos.y)
    
    playerInput()
    displayInfo()
    
stop()
end

原代码问题分析

  1. lua_pop(L, -3)是错误用法:lua_pop的第二个参数是弹出数量,而非栈索引,这会导致返回的表被错误弹出,引发内存异常。
  2. 动态分配Vector2完全冗余:直接用栈上变量即可完成存储,无需额外的MemAlloc/MemFree操作。

内容的提问来源于stack exchange,提问作者Planebagel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 11:52:55