加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

Lua编码的那些陷阱

发布时间:2020-12-14 22:01:23 所属栏目:大数据 来源:网络整理
导读:字符串连接符 “..” 当需要把多个小字符串拼接成一个大串的时候,例如,从一个sql结果集中取某列元素并将该元素组成以‘/’分割的字符串。 如果sql结果集是上万行,那么就会发现效率越来越低。这性能越来越低的原因是什么呢?这就要去追溯lua的垃圾收集算法


字符串连接符 “..”

当需要把多个小字符串拼接成一个大串的时候,例如,从一个sql结果集中取某列元素并将该元素组成以‘/’分割的字符串。

如果sql结果集是上万行,那么就会发现效率越来越低。这性能越来越低的原因是什么呢?这就要去追溯lua的垃圾收集算法,当Lua虚拟机发现程序使用太多的内存,它就会遍历它所有的数据结构,并进行释放它认为是垃圾的数据。一般情况下,这个算法有很好的性能,但下面的那段代码loop使得算法的效率极其低下。假设在loop中间,buff的大小已经是一个10kb的字符串, 一个sql结果中的所需要串连的成员的大小为10bytes, 那么buff .. row_tab.name .. “/” 新建的buff大小为10k+11bytes, 并且从buff中将10KB的字符串copy到新串中,也就是说每一行,都要移动10KB的内存,串连100行的时候(差不多1KB),Lua已经移动了1MB的内存。

也就是赋值语句中老的字符串变成了垃圾数据,两轮循环之后,将有两个老串包含超过20KB的垃圾数据,这个时候lua虚拟机会进行垃圾收集并释放这20KB的内存,问题在于,每两次循环就要进行一次垃圾收集,读取完一个sql结果集,所需的内存是原本内容的三倍。

而要获取最终的字符串,同时避免过多的垃圾回收,我们可以使用table.concat函数将一个列表的所有元素合并。

获取table的元素个数

当一个table为数组的时候,我们可能会使用以下两种用法中的一种,来获取该table的元素个数

我们修改table:

?

使用上述的两种方法,发现返回的table元素依旧是4。为什么呢,我们再把上面的代码修改为:

7
8
tab { 1 4 5 8 }
print ( # tab ???????????????????? --=====> 4
print . getn ) ???????? --=====> 4
?
[ ] 10
print --=====> 5
print --=====> 5
print ] ?????????????????? --=====> 10

我们可以看到,这段代码可以得到我们想要的结果。把table当数组使用的时候,该数组的大小不固定,可动态增长,在Lua中可以通过整数下标访问数组中的元素。当跳过数组下标时,像前一段代码一样,tab[5]、tab[6]、tab[7]、tab[8]的值均为nil,而table.getn和#tab两个函数一遇到为nil的时候就会返回了,就出现之前的结果(同样适用于table当集合使用,其结果返回为0)

函数重名:

在C语言或其他静态语言中,会对函数名进行检查,不允许重名的函数出现,但在lua,重名的函数是允许出现的,这就给我们的编码埋下一些隐患。当项目达到一定规模的时候,就很难保证不出现重名函数。那重名的函数会导致什么问题呢?我们看下面的代码:

原来lua虚拟机会把lua中的函数名都作为局部变量,存在局部变量表里,并在栈上开辟一个寄存器空间,在运行期,将新建一个closure,并存在已保留的寄存器里面。当有一个新定义的函数加入时,会新建一个closure,lua会把它压入栈,在调用该函数的时候,就会从栈顶开始找,找到匹配的函数名则返回。

?

堆栈溢出:

我们在运行lua的时候,有可能遇到这样一种报错 “stack overflow”,先看看下面一段代码

9
10
11
12
function func_r a )
a + 1
???? if > 100000 then
???????? print )
???? else
???????? func_r )
???? end
???? return a
end
?
x 1
func_r x )

语法上的确没有任何问题,但在执行的时候就会出现?stack overflow?的报错。是什么原因导致堆栈溢出呢?这个就要追究到Lua源码:Lua虚拟机会对堆栈进行一系列的检查(函数:luaL_checkstack),错误类型就有:

“too many arguments”,

“assume array is smaller than 2^40?“,

“string slice too long”,

“too many captures”,

“too many arguments to script”,

“too many nested functions”

例如,上面的代码就属于递归嵌套次数太多,默认限制20000。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

相关内容
推荐文章
站长推荐
热点阅读