Lua数据结构和内存占用分析(8)

理论计算出来的内存占用比实际消耗多了1724403-1724344 = 59字节,似乎两个字符串的消耗没有计算进来。那么这两个字符串”score” ”rank” 是否真正存在于stringTable答案是yes。只是在更早阶段,lua程序对代码文件进行词法分析,生成指令码的过程中,就已经调用luaS_newlstr创建了”score”和”rank”字符串了,因此不在上述代码的统计范围内,有兴趣的可以调试lua程序验证。

场景二:

去掉每条子表记录里面的key,直接按有序列表存储。

collectgarbage("stop");

before = collectgarbage("count");

tab = {}

for i = 1, 10000 do

    tab[100000+i] = {100000+i, i}

end

after = collectgarbage("count");

print("total mem:", (after - before)*1024)

total mem:      1404344.0

 

 

A,每个小表{100000+i, i}, sizeof(Table) + sizeof(TValue) * 2 = 88

B,大表有1W条记录,2^14 = 16384 > 10000sizeof(Table) + sizeof(Node) * 16384 = 524344

C,最终内存占用:88* 10000 + 524344 = 1404344

场景三:

如果列表只有2个变量,可以把两个数值合并,减少一层表的分配,那么就会减少场景二A子表的内存消耗。

collectgarbage("stop");

before = collectgarbage("count");

tab = {}

for i = 1, 10000 do

    tab[100000+i] = (100000 + i) << 14 + i

end

after = collectgarbage("count");

print("total mem:", (after - before)*1024)

total mem:      524344.0

 

由于value只是普通的数值,那么Node节点的TValue足够存储,不在单独分配额外内存,所以内存大小:sizeof(Table) + sizeof(Node) * 16384 = 524344

场景四:

如果还要继续压缩内存使用,可以考虑不要存1W条记录,存8192条记录如果也满足要求的话,这样可以减少一次hashtable的预分配。

collectgarbage("stop");

before = collectgarbage("count");

tab = {}

for i = 1, 8192 do

    tab[100000+i] = (100000 + i) << 14 + i

end

after = collectgarbage("count");

print("total mem:", (after - before)*1024)

total mem:      262200.0

 

A、大表的hashtable记录数2^13 = 8192, 那么刚好把节点使用完,没有浪费。

B、总体内存:sizeof(Table) + sizeof(Node) * 8192= 262200

所以,如果对lua table的动态内存管理比较清楚,可以在满足需求的情况进行一些优化,能够大幅压缩内存的占用,如上可以看到内存从最早的1724344 优化到262200 大概只有原来内存占用的1/7。当然了,也不能只考虑内存的占用,也要结合扩展性综合考虑,比如场景四里面由于少了一层表,会导致单条记录没法扩展字段。因此,不论是节省内存还是兼顾扩展性,是综合评估的结果,只有各方面利弊能够准确评估,才能做很好的tradeofff

场景五:

对比C/C++的实现

struct rankitem

{

     Uint64_t uid;

     Int score;

     Short rank_no;

};

 

struct ranklist

{

short num;

struct rankitem list[8192];

};

 

 

 

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/40d90a672028c9263a52f6444ac70320.html