lua API 小記3 lua虛擬機器初始化

2022-05-02 17:30:09 字數 3628 閱讀 6044

lua_state *lua_newstate (lua_alloc f, void *ud)

建立乙個新的獨立的lua虛擬機器. 引數指定了記憶體分配策略及其引數, 注意, 讓使用者可以定製記憶體分配策略是十分有用的, 比如在遊戲伺服器端使用lua, 我做過一次統記lua在執行的時候會大量的分配大小小於128位元組的記憶體塊, 在這樣的環境下, 使用lua原生的分配器就不太適合了, 還好在伺服器端, 我們往往已經實現了memory pool, 這時只需要寫乙個符合 lua_alloc 原型的介面卡, 然後指定為lua的記憶體分配器就可以了, 很靈活.

從lua的設計層面來說, lua只是記憶體分配器的使用者, 它只使用乙個簡單的介面來分配記憶體, 而不去實現如何分配, 畢竟記憶體分配不在lua的功能範圍內, 這樣使的lua變的更加緊湊, 它只是專注於實現lua本身, 而不需要去關注記憶體分配策略這樣的和lua本身無關的東西. 其實學習lua源**不光是為了更好的掌握lua, 也是為了學習lua中的體現出來的一些程式設計思想, lua是乙個高度的一致性的, 優雅的軟體作品

失敗返回null, 多是因為記憶體分配失敗了

該函式會建立棧

從該函式學習到的東西:  1. 當你製作乙個功能時, 最好是理清該功能的核心概念和需求, 然後去實現他們, 功能要模組化, 核心概念之間應該是概念一致的, 聯絡緊密的[談何容易, 只能是盡可能的, 隨時提醒自己要有這樣的想法].

2. 不要因為功能的實現問題而將乙個非該功能核心概念的東西加進來, 反之應該把這些東西抽象化作為使用者可配置的形式.[在實現時很容易發生"要用到某個功能了, 就是實現它"這樣的情況, 這樣並不好]就比如lua, 它的核心概念就是lua虛擬機器, 而記憶體分配只是在實現lua虛擬機器的過程中的要用到的一種東西, 但它本身不在lua的核心概念裡面, 所以把它暴露出來, 讓使用者自己去定製.

再說下去就是:除了系統最核心的功能, 其他的東西能用外掛程式的形式暴露給使用者, 使其可配置可擴充套件.

關於這個函式, 還要做更多的解釋, 比如我們看到的lua的絕大多數api的第乙個引數都是lua_state* l, 而這個l就是lua_newstate製造出來的, 那麼在分析原始碼的時候, 當然要去看看lua_newstate到底是幹了些什麼, lua_state的結構又是什麼, 要了解這些內容, 需要知道lua的內部組織結構, 下面是一張很概括但能反映其結構的圖

可以看出來, 在乙個獨立的lua虛擬機器裡, global_state是乙個全域性的結構, 而lua_state可以有多個

值得說明的是, 當呼叫lua_newstate的時候, 主要的工作就是1. 建立和初始化global_state 2. 建立乙個lua_state, 下面來詳細的講解global_state的內容和作用.

乙個lua虛擬機器中只有乙個, 它管理著lua中全域性唯一的資訊, 主要是以下功能

1. 記憶體分配策略及其引數, 在呼叫lua_newstate的時候配置它們. 也可以通過lua_getallocf和lua_setallocf隨時獲取和修改它

2. 字串的hashtable, lua中所有的字串都會在該hashtable中註冊.

3. gc相關的資訊. 記憶體使用統計量.

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上.

global_state主要是管理lua虛擬機器的全域性環境.

1. 要注意的是, 和nil, string, table一樣, lua_state也是lua中的一種基本型別, lua中的表示是tvalue

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的通訊.

lua_state主要是管理乙個lua虛擬機器的執行環境, 乙個lua虛擬機器可以有多個執行環境.

經過上面的分析, 可以看出newstate = [new 乙個 global_state] + [new 乙個 lua_state], 現在看一下它的流程, 很簡單

1. 新建乙個global_state和乙個lua_state.

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

3. 給l_s建立全域性表, 預分配l_s的callinfo和stack空間.

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

lua_state *luae_newthread (lua_state *l)

建立乙個新的lua_state, 預分配callinfo和stack空間, 並共享l_gt表, 注意, 雖然每個lua_state都有自己的l_gt, 但是這裡是卻將新建的lua_state的l_gt都指向主lua_state的l_gt.

注意, lua_state是lua執行的基礎[callinfo]和與c通訊的基礎[stack], 在新的lua_state上操作不會影響到原來的lua_state:), 這個是協程實現的基礎. 這裡順便提一下協程, 這裡先引一段lua創始人的話:" 我們不信任基於搶占式記憶體共享的多執行緒技術. 在 hopl **中, 我們寫道: "我們仍然認為, 如果在連 a=a+1 都沒有確定結果的語言中, 無人可以寫出正確的程式." 我們可以通過去掉搶占式這一點, 或是不共享記憶體, 就可以迴避這個問題."協程的基礎就是"去掉搶占式, 但共享記憶體", 這裡的共享是在lua虛擬機器的層面上的, 而不是通常意義上的share memory, 這裡的共享記憶體直接就指的是不同執行緒[lua_state]之間, 共享lua_state.l_gt全域性表, 全域性表可以作為不同協程之間的通訊環境, 當然也可以用lua_xmove函式, 協程的事先說到這裡.

乙個和多lua_state相關的函式是: 在同乙個lua虛擬機器裡傳遞不同lua_state的值

void lua_xmove (lua_state *from, lua_state *to, int n)
把from棧上的前n個值彈出, 並壓入到to棧中.
今天就先寫到這裡吧:)

虛擬機器Centos安裝docker小記

本書記錄是參考 spring cloud 與 docker 微服務架構實戰 第二版 這本書實現的。記錄簡單幾個命令,安裝順序如下 1.安裝docker所需的包 2.安裝stable倉庫 sudo yum config manager add repo 3.安裝docker ce,先更新yum 的包索...

虛擬機器 3 執行

位元組碼已經載入進來,肯定是你new了它,或者其他情況觸發了它的載入。打比如new了它,也就載入 鏈結 驗證 準備 解析 初始化了。再接著就是例項化。例項化,這個過程是啥,就是執行。這過程涉及到啥?怎麼樣把位元組碼轉化成機器碼 裝置可識別 虛擬機器抽象定義,new這個操作就是乙個棧幀,平時列印異常,...

將lua虛擬機器編譯為so

1 lua 預設編譯生成只是乙個靜態庫,當需要使用so時就需要對src makefile增加下面編譯規則 lua so liblua.so all t lua a lua t luac t lua so lua so core o lib o cc o shared 這一行前是乙個tab 最後在頂層...