1. 程式人生 > >Lua 虛擬機器的初始化

Lua 虛擬機器的初始化

轉自 https://blog.csdn.net/suhuaiqiang_janlay/article/details/56702381

一、Lua指令碼語言

1. 概述

Lua是一種指令碼程式語言,與一般指令碼語言不同,被稱為是嵌入式的指令碼語言。Lua最著名的應用是在暴雪公司的網路遊戲魔獸世界中。

Lua語言可以獨立進行程式設計,但這不是其主要的使用方式。Lua最典型的用法,是作為一個庫,嵌入到其他大型語言(稱為宿主語言)的應用程式之中,為應用程式提供引數配置或邏輯描述等功能,帶來前所未有的靈活性。

                                            

Lua常見的宿主語言有:C/C++、Java、.NET,甚至指令碼語言如PHP、Ruby。


2. Lua與相似解決方案的比較


Lua體積很小,往往使用靜態連結嵌入到程式內部,在釋出應用時不需要附帶任何的執行時支援。

3. 宿主語言中嵌入Lua的工作流程

(1)宿主語言建立Lua直譯器物件

(2)將宿主語言實現的Lua擴充套件,如函式等,註冊到Lua直譯器中,供其使用。

(3)讀入Lua源程式或預先編譯好的Lua程式。

(4)執行讀入的Lua程式。

二、Lua虛擬機器的初始化

Lua工作的核心是Lua虛擬機器,宿主語言在載入和執行Lua指令碼時,做的第一件事情就是建立並初始化Lua虛擬機器。

1. 建立Lua虛擬機器

lua_State *lua_newstate(lua_Alloc f, void *ud) API可以為我們建立一個新的獨立的Lua虛擬機器。

引數指定了虛擬機器中的記憶體分配策略,例如我們已經在自己的程式碼中實現了記憶體池,這時候只需要寫一個符合lua_Alloc原型的介面卡,然後指定為Lua的記憶體分配器就可以了,使得記憶體分配更加靈活。當然,如果不想自定義記憶體分配策略,也可以使用luaL_newstate,這樣Lua會幫你定義預設的記憶體分配策略。

我們可以先來看一下luaL_newstate的原始碼:

  1. // luaconf.h
  2. /* 
  3. @@ LUA_EXTRASPACE defines the size of a raw memory area associated with 
  4. ** a Lua state with very fast access.
     
  5. ** CHANGE it if you need a different size. 
  6. */
  7. #define LUA_EXTRASPACE        (sizeof(void *))
  8. // lstate.c
  9. /* 
  10. ** thread state + extra space 
  11. */
  12. typedefstruct LX {  
  13.   lu_byte extra_[LUA_EXTRASPACE];  
  14.   lua_State l;  
  15. } LX;  
  16. /* 
  17. ** Main thread combines a thread state and the global state 
  18. */
  19. typedefstruct LG {  
  20.   LX l;  
  21.   global_State g;  
  22. } LG;  
  23. // lstate.c
  24. LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {  
  25.   int i;  
  26.   lua_State *L;  
  27.   global_State *g;  
  28.   LG *l = cast(LG *, (*f)(ud, NULL, LUA_TTHREAD, sizeof(LG)));  
  29.   if (l == NULL) return NULL;  
  30.   L = &l->l.l;  
  31.   g = &l->g;  
  32.   ......  
  33.   return L;  
  34. }  

可見,通過luaL_newstate 建立Lua虛擬機器時,第一塊申請的記憶體將用來儲存global_State(全域性狀態機)和lua_State(主執行緒)例項。為了避免記憶體碎片的產生,同時減少記憶體分配和釋放的次數,Lua採用了一個小技巧:利用一個LG結構,把分配lua_State和global_State的行為關聯在一起。這個LG結構是在C檔案內部定義,而不存在公開的H檔案中,僅供該C程式碼檔案使用,因此這種依賴資料結構記憶體佈局的用法負作用不大。


2. 關於global_State和lua_State

在一個獨立的Lua虛擬機器中,global_State是一個全域性的結構, 而lua_State可以有多個


global_State

global_State結構,我們可以稱之為Lua全域性狀態機。從Lua的使用者角度來看,global_State結構是完全感知不到的:我們無法用Lua公開的API獲取到它的指標、控制代碼或引用,而且實際上我們也並不需要引用到它。但是對於Lua的實現來說,global_State是十分重要的部分。

它管理著Lua中全域性唯一的資訊,主要是以下功能:

(1)記憶體分配策略及其引數

在呼叫lua_newstate的時候配置它們. 也可以通過lua_getallocf和lua_setallocf隨時獲取和修改它

(2)字串的hashtable

全域性的字串雜湊表,即儲存那些短字串,使得整個虛擬機器中短字串只有一份例項。具體參見 Lua字串處理

(3)垃圾回收相關的資訊,記憶體使用統計量

(4)panic, 當無保護呼叫發生時, 會呼叫該函式, 預設是null, 可以通過lua_atpanic配置.(用於異常處理)

(5)登錄檔, 登錄檔是一個全域性唯一的table

(6)記錄lua中元方法名稱 和 基本型別的元表

[注意, lua中table和userdata每個例項可以擁有自己的獨特的元表--記錄在table和userdata的mt欄位, 其他型別是每個型別共享一個元表--就是記錄在這裡].

(7)upvalue連結串列

(8)主lua_State, 一個lua虛擬機器中, 可以有多個lua_State, lua_newstate會創建出一個lua_State(稱為主執行緒), 並邦定到global_state的主lua_State上

lua_State

執行緒,這裡執行緒的概念區別於作業系統的執行緒,實際上也是Lua中定義的一種狀態機。lua_State主要是管理一個lua虛擬機器的執行環境, 一個lua虛擬機器可以有多個執行環境。

(1)要注意的是, 和nil, string, table一樣,lua_State也是lua中的一種基本型別, lua中的表示是TValue {value = lua_State, tt = LUA_TTHREAD}

(2)lua_State的成員和功能

a. 棧的管理, 包括管理整個棧和當前函式使用的棧的情況

b. CallInfo的管理, 包括管理整個CallInfo陣列和當前函式的CallInfo

c. hook相關的, 包括hookmask, hookcount, hook函式等

d. 全域性表l_gt, 注意這個變數的命名, 很好的表現了它其實只是在本lua_State範圍內是全域性唯一的的, 和登錄檔不同, 登錄檔是lua虛擬機器範圍內是全域性唯一的e. gc的一些管理和當前棧中upvalue的管理 f.  錯誤處理的支援(3)從lua_State的成員可以看出來, lua_State最主要的功能就是函式呼叫以及和c的通訊.

3. lua_newstate函式的流程

(1)新建一個global_state和一個lua_State

(2)初始化, 包括給g_s建立登錄檔, g_s中各個型別的元表的預設值全部置為0

(3)給l_s建立全域性表, 預分配l_s的CallInfo和stack空間

(4)其中涉及到了記憶體分配統統使用lua_newstate傳進來的記憶體分配器分配