为什么LuaJIT在这个简单的代码中会产生“too many callbacks error”的错误?

我正在使用 LuaJIT,但在此代码中遇到了“太多回调”的异常。我知道生成的 c 回调数量有限,但据我所知,这应该只生成一个回调……对吧?

ffi = require('ffi')
ffi.cdef([[typedef double cpFloat;
typedef struct cpSpace cpSpace;
typedef struct cpBody cpBody;

cpSpace* cpSpaceNew(void);
cpBody* cpBodyNew(cpFloat mass, cpFloat moment);
cpBody* cpSpaceAddBody(cpSpace *space, cpBody *body);

typedef void (*cpSpaceBodyIteratorFunc)(cpBody *body, void *data);
void cpSpaceEachBody(cpSpace *space, cpSpaceBodyIteratorFunc func, void *data);

]])

chipmunk = ffi.load("chipmunk")
space = chipmunk.cpSpaceNew()
body = chipmunk.cpBodyNew(10, 100)
chipmunk.cpSpaceAddBody(space, body)

drawBody = function(body, x) end
CALL_COUNT = 5000
for i = 1, CALL_COUNT do
  chipmunk.cpSpaceEachBody(space, drawBody, nil)
end

如果将 CALL_COUNT 减少到 500,它就能正常工作而不出错。

异常如下:

错误:main.lua:25: too many callbacks
stack traceback:
    [C]: in function 'cpSpaceEachBody'
    mainmoon.lua:25: in main chunk
    [C]: in function 'require'
    main.lua:1: in main chunk
    [C]: in function 'require'
    [string "boot.lua"]:374: in function <[string "boot.lua"]:244>
    [C]: in function 'xpcall'

背景:我正在将 Chipmunk 集成到 Mac OS X 上的 Love2D 平台中。

点赞
用户282536
用户282536

在 LuaJIT 中,C 回调函数是有限资源。请参阅http://luajit.org/ext_ffi_semantics.html#callback

你的函数 cpSpaceEachBody 接受一个函数作为第二个参数。每次调用它时,都会创建一个新的 C 函数。除了创建过多的 C 函数之外,你还没有释放它们。因此,应该尽可能地使用较少的 C 函数。

在你的示例中,每次都使用相同的函数,因此可以进行简单修复:

ffi = require('ffi')
ffi.cdef([[typedef double cpFloat;
typedef struct cpSpace cpSpace;
typedef struct cpBody cpBody;

cpSpace* cpSpaceNew(void);
cpBody* cpBodyNew(cpFloat mass, cpFloat moment);
cpBody* cpSpaceAddBody(cpSpace *space, cpBody *body);

typedef void (*cpSpaceBodyIteratorFunc)(cpBody *body, void *data);
void cpSpaceEachBody(cpSpace *space, cpSpaceBodyIteratorFunc func, void *data);

]])

chipmunk = ffi.load("chipmunk")
space = chipmunk.cpSpaceNew()
body = chipmunk.cpBodyNew(10, 100)
chipmunk.cpSpaceAddBody(space, body)

drawBody = function(body, x) end
drawBody_C_func = ffi.cast("cpSpaceBodyIteratorFunc", drawBody)
CALL_COUNT = 5000
for i = 1, CALL_COUNT do
  chipmunk.cpSpaceEachBody(space, drawBody_C_func, nil)
end
drawBody_C_func:free()
2015-06-25 07:05:53