lua获取table占用内存的大小

1,500 阅读1分钟

计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+ (忘记了)

注:

  1. 不能处理循环引用问题。
  2. 只统计了 table,像 number/string/function 等,都没有统计