对于简单表tab = {}, 一般都是使用tab[#tab + 1] = xxxx 或者 table.insert(tab, xxx) 来插入数据,对于这种典型的场景,table使用的是array的方式存储数据。计算方式,sizeof(Table) + sizeof(TValue) * ArrayNum,其中sizeof(TValue) = 16。同样下面的代码,略作调整,100条记录实际的分配的Array节点也是128, 就是56 + 16 * 128 = 2104.
collectgarbage("stop");
before = collectgarbage("count");
tab = {}
for i = 1, 128 do
tab[#tab + 1] = i
end
after = collectgarbage("count");
print("total mem:", (after - before)*1024)
total mem: 2104.0
3、估算table嵌套类型的消耗
上面都是用的简单数据类型进行估算,现在考虑下当value是GCObject对象的情况(字符串、表、闭包)。针对一个Node节点,数据组成:
struct Node {
TValue i_val;
TKey i_key;
} Node;
因此,对于简单的数据类型,TValue里面的结构字段足以存储,但对于复杂类型,TValue里面只是存了一个对象指针GCObject*,而对象本身的内存大小还得单独核算。先看一个简单:
collectgarbage("stop");
before = collectgarbage("count");
tab = {}
tab[10000] = {i}
after = collectgarbage("count");
print("total mem:", (after - before)*1024)
total mem: 160.0
A、tab表 sizeof(Table) + sizeof(Node) * 1 = 88
B、{i}使用array来存储,实际消耗 sizeof(Table) + sizeof(TValue) * 1 = 72
C、所以整体消耗: 88 + 72 = 160
4、估算复杂table的数据内存消耗以及与C语言的对比
以一个简单的排行榜列表来进行多维度计算,预计10000条数据,以玩家uid作为key,每条记录存积分和名次。分多个场景进行评估。
场景一:
collectgarbage("stop");
before = collectgarbage("count");
tab = {}
for i = 1, 10000 do
tab[100000+i] = {score = 100000+i, rank = i}
end
after = collectgarbage("count");
print("total mem:", (after - before)*1024)
total mem: 1724344.0
A,首先涉及两个字符串”score” “rank” 的消耗。分别是25 + 5 = 30, 25 + 4 = 29 。
B,每个小表{score = 100000+i, rank = i}, sizeof(Table) + sizeof(Node) * 2 = 120。
C,大表有1W条记录,2^14 = 16384 > 10000。sizeof(Table) + sizeof(Node) * 16384 = 524344
D,最终内存占用:30 + 29 + 120 * 10000 + 524344 = 1724403