Lua 性能茁影,內(nèi)存優(yōu)化

1.字符串

  • 原理

    1. Lua 的字符串都是內(nèi)化的(internalized);這意味著字符串在 Lua 中都只有一份拷貝丧凤。每當(dāng)一個新字符串出現(xiàn)時募闲,Lua 會先檢查這個字符串是否已經(jīng)有一份拷貝,如果有愿待,就重用這份拷貝浩螺。內(nèi)化(internalization)使字符串比較及表索引這樣的操作變得非常快仍侥,但是字符串的創(chuàng)建會變慢要出。
    2. Lua 的字符串變量從來不會包含字符串本身,包含的只是字符串的引用农渊。這種實現(xiàn)加快了某些字符串操作患蹂。
  簡單的說lua維護了一個table存放了所有的字符串。
  任何新創(chuàng)建的字符串都會先hash去table查找一下砸紊,有的話直接返回字符串的引用传于。
  沒有的話創(chuàng)建個新的字符串放入table,返回新的字符串的引用醉顽。

  --引用列子
  local value = "a" 
  value  = value .."b"
  print(value )  -- 輸出 'ab'
  現(xiàn)在 lua string這個大table里沼溜,就有了  'a'  和 'ab' 兩個字符串了。value 實際引用的是 'ab'游添。

  --字符串的連接列子
  'x' .. 'y' .. 'z'
  這種就是 x找一回系草,xy找一回,xyz找一回唆涝。
  生成3個串 找3回最后table里有了'x'找都,'xy','xyz' 三個字符串了石抡。
  • 優(yōu)化

    1. 使用運算符 ' .. '
      每次拼接都需要申請新的空間檐嚣,舊的result對應(yīng)的空間會在某時刻被Lua的垃圾回收期GC,且隨著result不斷增長,越往后會開辟更多新的空間嚎京,并進行拷貝操作嗡贺,產(chǎn)生更多需要被GC的空間,所以性能降低鞍帝。

    2. 使用table.concat (table [, sep [, start [, end]]])函數(shù)
      table.concat 底層拼接字符串的方式也是使用運算符.. 诫睬,但是其使用算法減少了使用運算符..的次數(shù),減少了GC帕涌,從而提高效率摄凡。

2.Table

  • 原理

    1. Lua 實現(xiàn)表的算法頗為巧妙。每個表包含兩部分:數(shù)組(array)部分和哈希(hash)部
      分蚓曼,數(shù)組部分保存的項(entry)以整數(shù)為鍵(key)亲澡,從 1 到某個特定的 n,(稍后會討
      論 n 是怎么計算的纫版。)所有其他的項(包括整數(shù)鍵超出范圍的)則保存在哈希部分床绪。
      顧名思義,哈希部分使用哈希算法來保存和查找鍵值其弊。它使用的是開放尋址(open
      address)的表癞己,意味著所有的項都直接存在哈希數(shù)組里。鍵值的主索引由哈希函數(shù)給出梭伐;
      如果發(fā)生沖突(兩個鍵值哈希到相同的位置)痹雅,這些鍵值就串成一個鏈表,鏈表的每個元素
      占用數(shù)組的一項糊识。
    2. 執(zhí)行擴容的過程叫做rehash绩社,每次rehash時,會遍歷整個table的數(shù)組部分和哈希表部分技掏,統(tǒng)計其中有效的鍵值對铃将,大小不夠项鬼,則會擴容哑梳,擴容后的大小為2的整數(shù)冪次方,且保證rehash操作后整個數(shù)組部分的使用率大于50%绘盟。每次rehash都很耗時鸠真,使用table,我們應(yīng)該盡量減少rehash龄毡。
  • 優(yōu)化

    1. 初始化優(yōu)化減少吠卷, rehash的次數(shù).
    local param = {};param.type = 1;param.id = 1; param.name = "lua"; 
    --優(yōu)化成
    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
    --優(yōu)化為
    local a = {0,0,0}
    for i = 1, 3 do
     a[i] = true
    end
    
    當(dāng)新key要加入,table大小從0->1,1->2,2->4,類似這種預(yù)先分配好空間能減少內(nèi)存分配。

3.局部變量

  • 原理

    Lua 使用了一個基于寄存器的虛擬機沦零。這些「寄存器」
    跟 CPU 中真實的寄存器并無關(guān)聯(lián)祭隔,因為這種關(guān)聯(lián)既無可移植性,也受限于可用的寄存器數(shù)
    量路操。Lua 使用一個棧(由一個數(shù)組加上一些索引實現(xiàn))來存放它的寄存器疾渴。每個活動的
    (active)函數(shù)都有一份活動記錄(activation record)千贯,活動記錄占用棧的一小塊,存放
    著這個函數(shù)對應(yīng)的寄存器搞坝。因此搔谴,每個函數(shù)都有其自己的寄存器。由于每條指令只有 8 個
    bit 用來指定寄存器桩撮,每個函數(shù)便可以使用多至 250 個寄存器敦第。
    Lua 的寄存器如此之多,預(yù)編譯時便能將所有的局部變量存到寄存器中店量。所以芜果,在 Lua 中
    訪問局部變量是很快的。
  • 優(yōu)化

    1. 高頻調(diào)用類優(yōu)化
    local x = math.sin(i) 
    --優(yōu)化成
    local sin = math.sin
    local x = sin(i)
    
    1. 在大項目基于元表融师,元方法實現(xiàn)的類和繼承時师幕,local優(yōu)化是很高效的。
      local變量優(yōu)化

4.元表與元方法

  • 原理

因為Lua本身是沒有面向?qū)ο笾С值奈芴玻陧椖块_發(fā)中需要面向?qū)ο缶幊膛啵谑呛芏嗳擞肔ua本身的數(shù)據(jù)結(jié)構(gòu)table+元表來模擬面向?qū)ο髮崿F(xiàn)類、繼承疼鸟、多重繼承后控。當(dāng)元方法 __index 和 __newindex 變成函數(shù)時,會因為 函數(shù)本身的復(fù)雜度導(dǎo)致邏輯消耗時間變多空镜。在大型項目里是不小的性能開銷浩淘。

  1. 元方法 __index 用來對表訪問,訪問規(guī)則:
    1.在表中查找吴攒,如果找到张抄,返回該元素,找不到則繼續(xù)洼怔。
    2.判斷該表是否有元表署惯,如果沒有元表,返回 nil镣隶,有元表則繼續(xù)极谊。
    3.判斷元表有沒有 __index 方法,如果 __index 方法為 nil安岂,則返回 nil轻猖;如果 __index 方法是一個表,則重復(fù) 1域那、2咙边、3;如果 __index 方法是一個函數(shù),則返回該函數(shù)的返回值败许。

  2. 元方法 __newindex 用來對表更新友瘤,更新規(guī)則:
    1.如果是表已存在的索引鍵,則直接更新檐束,沒有的話就繼續(xù)辫秧。
    2.解釋器就會查找__newindex 元方法:如果存在則調(diào)用這個函數(shù)而不進行賦值操作。
    3.如果不存在則直接對表賦值被丧。

  • 優(yōu)化

    1. 利用local話盟戏,提升訪問速度。
    2. C++甥桂、C 去實現(xiàn)柿究,畢竟C、C++的效率高黄选。

5.函數(shù)

  1. 參數(shù)優(yōu)先boolean, number, string, function蝇摸,少table。防止new table 頻繁rehash办陷,gc貌夕。
  2. Lua編譯一個函數(shù)時,會為它生成一個原型(prototype)民镜,其中包含了函數(shù)體對應(yīng)的虛擬機指令啡专、函數(shù)用到的常量值(數(shù),文本字符串等等)和一些調(diào)試信息制圈。在運行時们童,每當(dāng)Lua執(zhí)行一個形如function...end 這樣的表達式時,它就會創(chuàng)建一個新的數(shù)據(jù)對象鲸鹦,其中包含了相應(yīng)函數(shù)原型的引用慧库、環(huán)境(environment,用來查找全局變量的表)的引用以及一個由所有upvalue引用組成的數(shù)組馋嗜,而這個數(shù)據(jù)對象就稱為閉包齐板。由此可見,函數(shù)是編譯期概念嵌戈,是靜態(tài)的覆积,而閉包是運行期概念听皿,是動態(tài)的熟呛。
function f1(n)
  local function f2()
    --用來查找全局變量的表)的引用以及一個由所有upvalue引用組成的數(shù)組
    -{n}
    print(n)
  end
  n=n + 10
  return  f2
end
g1  = f1(1979)
g1()--打印出1989

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市尉姨,隨后出現(xiàn)的幾起案子庵朝,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件九府,死亡現(xiàn)場離奇詭異椎瘟,居然都是意外死亡,警方通過查閱死者的電腦和手機侄旬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進店門肺蔚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人儡羔,你說我怎么就攤上這事宣羊。” “怎么了汰蜘?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵仇冯,是天一觀的道長。 經(jīng)常有香客問我族操,道長苛坚,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任色难,我火速辦了婚禮泼舱,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘枷莉。我一直安慰自己柠掂,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布依沮。 她就那樣靜靜地躺著涯贞,像睡著了一般。 火紅的嫁衣襯著肌膚如雪危喉。 梳的紋絲不亂的頭發(fā)上宋渔,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天,我揣著相機與錄音辜限,去河邊找鬼皇拣。 笑死,一個胖子當(dāng)著我的面吹牛薄嫡,可吹牛的內(nèi)容都是我干的氧急。 我是一名探鬼主播,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼毫深,長吁一口氣:“原來是場噩夢啊……” “哼吩坝!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起哑蔫,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤钉寝,失蹤者是張志新(化名)和其女友劉穎弧呐,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體嵌纲,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡俘枫,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了逮走。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鸠蚪。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖师溅,靈堂內(nèi)的尸體忽然破棺而出邓嘹,到底是詐尸還是另有隱情,我是刑警寧澤险胰,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布汹押,位于F島的核電站,受9級特大地震影響起便,放射性物質(zhì)發(fā)生泄漏棚贾。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一榆综、第九天 我趴在偏房一處隱蔽的房頂上張望妙痹。 院中可真熱鬧,春花似錦鼻疮、人聲如沸怯伊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽耿芹。三九已至,卻和暖如春挪哄,著一層夾襖步出監(jiān)牢的瞬間吧秕,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工迹炼, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留砸彬,地道東北人。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓斯入,卻偏偏與公主長得像砂碉,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子刻两,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,781評論 2 354