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


最大差别在于相同长字符串创建的内存消耗,Lua5.1.4由于统一用stringtable保存一份拷贝,所以内存消耗可以忽略不记,但Lua5.3.4由于会产生不同副本拷贝,消耗明显。

2.1.4 table重复字符串key对内存影响?

对于短字符串,只会在stringtable中存在一份拷贝,对内存没有什么影响。对于长字符串,需要分两种场合看:

for i =1, 1000 do

Tab[i] = {ccccccccccccccccccccccccccccccccccccccc=i}

end

或者

Tab[1] = {ccccccccccccccccccccccccccccccccccccccc=1}

Tab[2] = {ccccccccccccccccccccccccccccccccccccccc=2}

Tab[3] = {ccccccccccccccccccccccccccccccccccccccc=3}

...

Tab[100] = {ccccccccccccccccccccccccccccccccccccccc=100}

对于这两种情况,由于lua程序进行代码文件词法分析时,第一种调用一次luaS_newlstr创建”ccccccccccccccccccccccccccccccccccccccc”, 而第二种会调用100次。正如我们前面的分析,长字符串每次调用都会生成一份新的拷贝,所以第二种情况会有N份的字符串内存消耗。

我们服务器的表资源,转表后都是按第二种形态存在,所以一定要切记key的字符串长度不要超过40,否则产生无谓的内存浪费和大量的GC对象,影响GC效率。

2.2 table类型

在开发过程中,table是最常见的数据结构,每条记录对外都是key-value的方式来读写。他的底层是用array + hashtable的方式管理数据的,但对外是透明的。不论array还是hashtable都是连续的内存分布。在查找时:

1. 如果key是整型并且 key > 1 and key < max_array_size, 直接取array[key]数据

2. 其他情况,默认读取hashtableHashtable的管理方有些特别,当不同key hash到同一个node时,用链表来维护这些冲突节点。与stringtable 链表节点动态分配的方法不同, HashTable使用空闲链表来维护冲突节点。

 

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

2.2.1  Array or HashTable

首先说一种典型的情况,调用table.insert 或者table[#table + 1] 按序插入列表的,就是存放在array里面。

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

2.2.2 rehash动态扩容原理

  在插入新节点时,如果通过freelist找不到可用节点就触发rehash。在新创建table时,node节点数量为0,当插入第1条数据时触发内存分配2^0=1个内存节点。当插入第2条记录时,因为节点都已经使用,所以又触发rehash,分配2^1=2个内存节点。依次类推,在插入第359时,触发分配一个更大的内存,可以简单理解成重新分配一块oldsize * 2 的内存,把原有的hashTable的数据重新hash插入到新的内存中,再释放掉原有的内存。综上,每次内存的增长都是按2的指数倍来增长。

1Rehash导致的cpu消耗

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

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