轉自:http://www.cnblogs.com/ringofthec/archive/2010/11/09/lua_State.htmlhtml
lua_State *lua_newstate (lua_Alloc f, void *ud)編程
建立一個新的獨立的lua虛擬機. 參數指定了內存分配策略及其參數, 注意, 讓用戶能夠定製內存分配策略是十分有用的, 好比在遊戲服務器端使用lua, 我作過一次統記lua在運行的時候會大量的分配大小小於128字節的內存塊, 在這樣的環境下, 使用lua原生的分配器就不太適合了, 還好在服務器端, 咱們每每已經實現了memory pool, 這時只須要寫一個符合 lua_Alloc 原型的適配器, 而後指定爲lua的內存分配器就能夠了, 很靈活.api
從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
能夠看出來, 在一個獨立的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 {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的通訊.
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棧中.