计Lua table 的内存大小是没有现成的接口的,从源码上来看,table的类型定义如下
typedef struct Table {
CommonHeader;
lu_byte flags; /* 1<<p means tagmethod(p) is not present */
lu_byte lsizenode; /* log2 of size of 'node' array */
unsigned int alimit; /* "limit" of 'array' array */
TValue *array; /* array part */
Node *node;
Node *lastfree; /* any free position is before this position */
struct Table *metatable;
GCObject *gclist;
} Table;
所以,一个table占用内存的大小为,
static int gettableSize (Table *t){
if ( t == NULL ) return 0;
int nodeSize = allocsizenode(t) ;
int s = sizeof(Table) + sizeof(TValue) * t->alimit + nodeSize * sizeof(Node);
return s;
}
int lua_gettableMemHelp (lua_State *L, int idx) {
Table *t = gettable(L,idx);
int s = gettableSize(t);
s += gettableSize(t->metatable);
return s;
}
因为lua是不能直接获取Table的,所以要改下源码
static Table *gettable (lua_State *L, int idx) {
TValue *t = index2value(L, idx);
api_check(L, ttistable(t), "table expected");
return hvalue(t);
}
当然,需要考虑到table的key/value仍然可能是table,故
int getAllocSize(lua_State *L,int idx) {
int ret = lua_gettableMem(L,idx);
lua_pushvalue(L, idx);//将table拷到顶层
int it = lua_gettop(L);//备份位置
lua_pushnil(L);// next的第一个key为nil
while (lua_next(L,it) != 0) {
//此时 -1=>value, -2=>key, it=>table
if ( lua_istable(L,-2) ){
ret += getAllocSize(L,-2);
}
if ( lua_istable(L,-1) ){
ret += getAllocSize(L,-1);
}
lua_pop(L,1);
//此时 -1=>key, it=>table
}
lua_pop(L,1);//因为将 将table拷到顶层 ,所以需要pop ,
//又因为 key会在调用next时被吃点。所以不用pop nil
return ret;
}
在lua中使用
local testlib = require("testlib")
local d = {12}
local c = {1,1,1,1,1,d}
local a = {1,2,3,c,2}
local b = {["abc"]=a}
print(testlib.luacallcfunc(b))
--输出 400+ (忘记了)
注:
- 不能处理循环引用问题。
- 只统计了 table,像 number/string/function 等,都没有统计