Lua 性能,内存优化

1.字符串

  • 原理

    1. Lua 的字符串都是内化的(internalized);这意味着字符串在 Lua 中都只有一份拷贝。每当一个新字符串出现时,Lua 会先检查这个字符串是否已经有一份拷贝,如果有,就重用这份拷贝。内化(internalization)使字符串比较及表索引这样的操作变得非常快,但是字符串的创建会变慢。
    2. Lua 的字符串变量从来不会包含字符串本身,包含的只是字符串的引用。这种实现加快了某些字符串操作。
  简单的说lua维护了一个table存放了所有的字符串。
  任何新创建的字符串都会先hash去table查找一下,有的话直接返回字符串的引用。
  没有的话创建个新的字符串放入table,返回新的字符串的引用。

  --引用列子
  local value = "a" 
  value  = value .."b"
  print(value )  -- 输出 'ab'
  现在 lua string这个大table里,就有了  'a'  和 'ab' 两个字符串了。value 实际引用的是 'ab'。

  --字符串的连接列子
  'x' .. 'y' .. 'z'
  这种就是 x找一回,xy找一回,xyz找一回。
  生成3个串 找3回最后table里有了'x','xy','xyz' 三个字符串了。
  • 优化

    1. 使用运算符 ' .. '
      每次拼接都需要申请新的空间,旧的result对应的空间会在某时刻被Lua的垃圾回收期GC,且随着result不断增长,越往后会开辟更多新的空间,并进行拷贝操作,产生更多需要被GC的空间,所以性能降低。

    2. 使用table.concat (table [, sep [, start [, end]]])函数
      table.concat 底层拼接字符串的方式也是使用运算符.. ,但是其使用算法减少了使用运算符..的次数,减少了GC,从而提高效率。

2.Table

  • 原理

    1. Lua 实现表的算法颇为巧妙。每个表包含两部分:数组(array)部分和哈希(hash)部
      分,数组部分保存的项(entry)以整数为键(key),从 1 到某个特定的 n,(稍后会讨
      论 n 是怎么计算的。)所有其他的项(包括整数键超出范围的)则保存在哈希部分。
      顾名思义,哈希部分使用哈希算法来保存和查找键值。它使用的是开放寻址(open
      address)的表,意味着所有的项都直接存在哈希数组里。键值的主索引由哈希函数给出;
      如果发生冲突(两个键值哈希到相同的位置),这些键值就串成一个链表,链表的每个元素
      占用数组的一项。
    2. 执行扩容的过程叫做rehash,每次rehash时,会遍历整个table的数组部分和哈希表部分,统计其中有效的键值对,大小不够,则会扩容,扩容后的大小为2的整数幂次方,且保证rehash操作后整个数组部分的使用率大于50%。每次rehash都很耗时,使用table,我们应该尽量减少rehash。
  • 优化

    1. 初始化优化减少, rehash的次数.
    local param = {};param.type = 1;param.id = 1; param.name = "lua"; 
    --优化成
    local param = {type= 1, id = 1,name = "lua"};
    

    2. 扩容

    local a = {}
    --a = 0
    for i = 1, 3 do
     a[i] = true
     --i == 1 a == 1
     --i == 2 a == 2
     --i == 3 a == 4
    end
    --优化为
    local a = {0,0,0}
    for i = 1, 3 do
     a[i] = true
    end
    
    当新key要加入,table大小从0->1,1->2,2->4,类似这种预先分配好空间能减少内存分配。

3.局部变量

  • 原理

    Lua 使用了一个基于寄存器的虚拟机。这些「寄存器」
    跟 CPU 中真实的寄存器并无关联,因为这种关联既无可移植性,也受限于可用的寄存器数
    量。Lua 使用一个栈(由一个数组加上一些索引实现)来存放它的寄存器。每个活动的
    (active)函数都有一份活动记录(activation record),活动记录占用栈的一小块,存放
    着这个函数对应的寄存器。因此,每个函数都有其自己的寄存器。由于每条指令只有 8 个
    bit 用来指定寄存器,每个函数便可以使用多至 250 个寄存器。
    Lua 的寄存器如此之多,预编译时便能将所有的局部变量存到寄存器中。所以,在 Lua 中
    访问局部变量是很快的。
  • 优化

    1. 高频调用类优化
    local x = math.sin(i) 
    --优化成
    local sin = math.sin
    local x = sin(i)
    
    1. 在大项目基于元表,元方法实现的类和继承时,local优化是很高效的。
      local变量优化

4.元表与元方法

  • 原理

因为Lua本身是没有面向对象支持的,但在项目开发中需要面向对象编程,于是很多人用Lua本身的数据结构table+元表来模拟面向对象实现类、继承、多重继承。当元方法 __index 和 __newindex 变成函数时,会因为 函数本身的复杂度导致逻辑消耗时间变多。在大型项目里是不小的性能开销。

  1. 元方法 __index 用来对表访问,访问规则:
    1.在表中查找,如果找到,返回该元素,找不到则继续。
    2.判断该表是否有元表,如果没有元表,返回 nil,有元表则继续。
    3.判断元表有没有 __index 方法,如果 __index 方法为 nil,则返回 nil;如果 __index 方法是一个表,则重复 1、2、3;如果 __index 方法是一个函数,则返回该函数的返回值。

  2. 元方法 __newindex 用来对表更新,更新规则:
    1.如果是表已存在的索引键,则直接更新,没有的话就继续。
    2.解释器就会查找__newindex 元方法:如果存在则调用这个函数而不进行赋值操作。
    3.如果不存在则直接对表赋值。

  • 优化

    1. 利用local话,提升访问速度。
    2. C++、C 去实现,毕竟C、C++的效率高。

5.函数

  1. 参数优先boolean, number, string, function,少table。防止new table 频繁rehash,gc。
  2. Lua编译一个函数时,会为它生成一个原型(prototype),其中包含了函数体对应的虚拟机指令、函数用到的常量值(数,文本字符串等等)和一些调试信息。在运行时,每当Lua执行一个形如function...end 这样的表达式时,它就会创建一个新的数据对象,其中包含了相应函数原型的引用、环境(environment,用来查找全局变量的表)的引用以及一个由所有upvalue引用组成的数组,而这个数据对象就称为闭包。由此可见,函数是编译期概念,是静态的,而闭包是运行期概念,是动态的。
function f1(n)
  local function f2()
    --用来查找全局变量的表)的引用以及一个由所有upvalue引用组成的数组
    -{n}
    print(n)
  end
  n=n + 10
  return  f2
end
g1  = f1(1979)
g1()--打印出1989

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,254评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,875评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,682评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,896评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,015评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,152评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,208评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,962评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,388评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,700评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,867评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,551评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,186评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,901评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,689评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,757评论 2 351