2012/07/18 18:39:58 [error] 20154#0: *33286 lua handler aborted: runtime error: table overflow
stack traceback:
[C]: in function 'cdef'
.../libsrc/ngx_ffi.lua:13: in function <...libsrc/ngx_ffi.lua:1>, client: 127.0.0.1, server: 127.0.0.1, request: .....
local ngx = require("ngx")
local ffi = require("ffi")
ffi.cdef[[
typedef struct { void* ev_ptr; void* char_ptr; } bif_result;
bif_result* lib_search(const char* indexname, const char* key, const char* start, const char* end, const char* datatype, const char* rowstart, const char* pa
gesize);
void free_bif_result(bif_result* ptr);
]]
local function get_char(s)
if s == nil then
return nil
end
char_s = ffi.new("char[?]", #s+1)
ffi.copy(char_s, s)
return char_s
end
local lsearch = ffi.load('lsearch')
local r = lsearch.lib_search(get_char(ngx.var.indexname), get_char(ngx.var.key), get_char(ngx.var.start), get_char(ngx.var.d_end), get_char(ngx.var.datatype
), nil, nil)
local res = ffi.string(r.char_ptr)
ngx.say(res)
lsearch.free_bif_result(r)
ngx = nil
ffi = nil
On Wed, Jul 18, 2012 at 4:33 AM, Zhaohao Liang <lian...@gmail.com> wrote:
> 使用openresty+luajit+ffi调用一个C库,请求多了后返回500,error_log显示:
>
>> 2012/07/18 18:39:58 [error] 20154#0: *33286 lua handler aborted: runtime
>> error: table overflow
>> stack traceback:
>> [C]: in function 'cdef'
>> .../libsrc/ngx_ffi.lua:13: in function <...libsrc/ngx_ffi.lua:1>,
>> client: 127.0.0.1, server: 127.0.0.1, request: .....
>
>
> ngx_ffi.lua的代码如下:
>
>> local ngx = require("ngx")
>> local ffi = require("ffi")
>>
>>
>>
>> ffi.cdef[[
>> typedef struct { void* ev_ptr; void* char_ptr; } bif_result;
>> bif_result* lib_search(const char* indexname, const char* key, const char*
>> start, const char* end, const char* datatype, const char* rowstart, const
>> char* pa
>> gesize);
>> void free_bif_result(bif_result* ptr);
>> ]]
>>
貌似你每请求都调用 ffi.cdef?建议把 ngx_ffi.lua 实现为一个真正的 Lua 模块,这样就可以享受只加载一次的好处,见:
http://wiki.nginx.org/HttpLuaModule#Data_Sharing_within_an_Nginx_Worker
你遇见的 table overflow 的错误很容易通过下面这个独立的 Lua 脚本复现:
-- test.lua
local ffi = require "ffi"
while true do
ffi.cdef[[
typedef struct { void* ev_ptr; void* char_ptr; } bif_result;
]]
end
命令行上的执行结果如下:
$ /usr/local/openresty/luajit/bin/luajit-2.0.0-beta10 test.lua
/usr/local/openresty/luajit/bin/luajit-2.0.0-beta10: table overflow
stack traceback:
[C]: in function 'cdef'
a.lua:6: in main chunk
[C]: ?
所以只要把 ffi.cdef 移出循环就不会溢出了。(而在你的场景中,则是把 ffi.cdef 调用移进 Lua 模块加载代码。)
可以参考一下我的 lua-resty-string 库中的 resty.md5 模块的实现:
https://github.com/agentzh/lua-resty-string/blob/master/lib/resty/md5.lua
Best regards,
-agentzh
--
--
邮件来自列表“openresty”,专用于技术讨论!
订阅: 请发空白邮件到 openresty...@googlegroups.com
发言: 请发邮件到 open...@googlegroups.com
退订: 请发邮件至 openresty+...@googlegroups.com
归档: http://groups.google.com/group/openresty
官网: http://openresty.org/
仓库: https://github.com/agentzh/ngx_openresty
教程: http://openresty.org/download/agentzh-nginx-tutorials-zhcn.html
---
您收到此邮件是因为您订阅了Google群组上“openresty”群组中的主题。
要退订此主题,请访问https://groups.google.com/d/topic/openresty/zGxwOqUN4fc/unsubscribe。
要退订此群组及其所有主题,请发送电子邮件到openresty+...@googlegroups.com。
如需查看此讨论,请访问 https://groups.google.com/d/msgid/openresty/24ad9c9e-9a3a-4ce4-a461-1717b1dbecc4n%40googlegroups.com。
貌似你的attr_api.lua不完整,是否缺少一些函数包装?4o reply:你遇到的
table overflow
错误通常是由于在每个请求中重复调用ffi.cdef
导致的。LuaJIT 的 FFI 模块会将每次的cdef
声明存储在内部表中,重复声明相同的结构或函数会导致该表迅速膨胀,最终触发table overflow
错误。问题分析
在你的
attr_api.lua
文件中,ffi.cdef
被放置在模块的顶层,这本身是正确的做法。然而,你提到仍然出现table overflow
错误,可能是由于以下原因之一:
模块未被正确缓存:如果在每个请求中都重新加载
attr_api.lua
模块(例如使用dofile
或未正确使用require
),会导致ffi.cdef
被多次执行。模块定义不规范:如果
attr_api.lua
没有正确返回模块表,或者模块的结构不规范,可能会导致 Lua 的模块缓存机制失效,从而在每次请求时重新加载模块。解决方案
为避免
table overflow
错误,建议按照以下方式组织你的代码:attr_api.lua
local ffi = require "ffi" ffi.cdef[[ int Attr_API(int attr, int iValue); ]] local lib = ffi.load("/usr/servers/nginx/conf/lua/libAttr_API.so") local _M = {} function _M.attr_api(attr, value) local ok, err = pcall(lib.Attr_API, attr, value) if not ok then ngx.log(ngx.ERR, "Attr_API call failed: ", err) end end return _M
cdnlog.lua
local attr = require("attr_api") local args = ngx.req.get_uri_args() local k = args["k"] if k then attr.attr_api(12345, 1) end
请确保:
使用
require
加载模块:require
会缓存模块,避免重复加载。模块返回模块表:
attr_api.lua
应该返回一个表(如_M
),以供其他模块使用。避免在请求处理函数中调用
ffi.cdef
:ffi.cdef
应该只在模块加载时调用一次。其他建议
避免重复声明:确保没有在多个模块中重复声明相同的 C 函数或结构。
模块化管理 C 函数声明:将所有的
ffi.cdef
声明集中在一个模块中,供其他模块引用。使用
resty.core
:在init_worker_by_lua_block
中加载resty.core
,可以提高性能并减少内存使用。 (a problem with lua ffi in openresty · Issue #1562 - GitHub)通过上述方法,可以有效避免
table overflow
错误,并提高 OpenResty 应用的稳定性和性能。
Claude-3.7-Sonnet reply:
你的模块结构存在一些问题,这可能是导致 table overflow 的原因。主要问题点和解决方案如下:
attr_api.lua
文件中的函数定义不完整 - 没有定义attr_api
函数,但在cdnlog.lua
中却调用了它。
ffi.cdef
应该只在模块加载时执行一次,但当前实现可能导致它被重复执行。
pcall
的使用方式有误,没有正确包装函数调用。以下是修正后的
attr_api.lua
文件:local ffi = require "ffi" -- 正确定义模块 local _M = { _VERSION = "0.1" } -- 仅在模块加载时执行一次 ffi.cdef[[ int Attr_API(int attr, int iValue); ]] -- 加载C库,只需执行一次 local myffi = ffi.load("/usr/servers/nginx/conf/lua/libAttr_API.so") -- 正确定义模块中的函数 function _M.attr_api(id, value) local ok, err = pcall(function() return myffi.Attr_API(id, value) end) if not ok then ngx.log(ngx.ERR, "Attr_API call failed: ", err) end return ok end return _M
此外,还有几点建议:
- 确保模块只被加载一次。在 Nginx 配置中,可以使用
init_by_lua_block
或init_by_lua_file
来预加载模块:init_by_lua_block { require("attr_api") }
检查是否有多个 worker 进程同时运行,每个进程都会加载一次模块,但这是正常的。
确保
libAttr_API.so
库的路径正确且文件存在。考虑添加错误处理和日志记录,特别是在 C 函数调用失败时。
这个问题很可能是由于 FFI 的缓存机制和模块加载问题导致的。正确实现模块结构后,应该能解决 table overflow 的问题。
Thanks
Liang Zhaohao
lan hust <hustl...@gmail.com> 于2025年4月26日周六 16:36写道:
@Zhaohao Liang 请问这个是怎么解决的?
--
您收到此邮件是因为您订阅了Google群组上的“openresty”群组。
要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到openresty+...@googlegroups.com。
如需查看此讨论,请访问 https://groups.google.com/d/msgid/openresty/CAMs7pcc%2B%3Doib9N%2Bv67rSmmwC4zx%2B0AMm82pt5MiBf--KzEynVw%40mail.gmail.com。