以10节点来说明,这是因为在插入第9条数据后,print打印,系统创建了一个”0.2841796875”字符串,导致节点10在统计消耗的时候计算进去了,具体消耗长度为 25 + 实际长度= 25 + 12 = 37字节,与节点10的消耗吻合。同理节点18的消耗为25 + len(“0.5”) = 28
问题二:因为节点10、18、34本身也print打印了字符串,怎么它后面的11、19、35就没有消耗内存?
以11为例,理论上节点10打印的”0.0361328125”会消耗内存,但这个字符串在节点6已经创建过了,由于所有短字符串都在stringtable进行管理,只有一份拷贝,所以不再消耗内存。
问题三:为什第一个节点内存消耗明显偏高?
这是因为for循环里面local cur = collectgarbage("count")调用,触发了Lua_state->stack指向的内存空间的动态扩容,原理有点类似HashTable内存不够的再分配机制。
综上三个问题,可以把代码调整一下再看:
tab = {}
text = "diff mem"
collectgarbage("stop")
before = collectgarbage("count");
for i = 1, 100 do
if i == 1 then before = collectgarbage("count"); end
tab[10000 + i] = i
local cur = collectgarbage("count")
print(text, cur - before)
before = collectgarbage("count");
end
可以看到,在1、2、3、5、9、17等位置触发内存再分配,对应重新分配的内存是2^0=1、2^1=2、2^2=4、8、16、32大小。NewSize-OldSize差值即新增内存,分别为1-0=1、2-1=1、4-2=2、8-4=4、16-8=8、32-16=16,而单个节点大小为0.03125K,整体每次新增内存与上面截图完全吻合。
2.2.3 估算table的内存消耗创建一个最简单的表{}, lua在调用luaH_new初始化时并不会动态分配array和hashtable指向的内存,只是创建一个最简单的table管理结构,所以消耗的内存为sizeof(Table) = 56。
1、估算table中hashtable的内存消耗
每个Node节点消耗sizeof(Node) = 32。所以对于简单数据(整型、浮点、bool)相对比较好估算,sizeof(Table) + sizeof(Node) * NodeNum。 例如上面的代码,100条记录实际分配的Node节点2^7=128,就是56 + 32 * 128 = 4152
collectgarbage("stop");
before = collectgarbage("count");
tab = {}
for i = 1, 128 do
tab[10000+i] = i
end
after = collectgarbage("count");
print("total mem:", (after - before)*1024)
total mem: 4152.0
2、估算table中有序数组的内存消耗