虛擬機

虛擬機分兩部分:管理資源,執行指令。

執行指令部分:
協程,所有協程共享一個虛擬機。也可以理解成線程,但是同時只有一個線程正在執行。

  1. 維護運行棧:局部變量棧,函數調用棧。
  2. 維護狀態:stop,runing,finish,error。
  3. 提供接口:控制協程執行和暫停,通過棧傳入參數獲取結果。
  4. 讀取執行指令:實際比較簡單,就是讀取執行,判斷指令類型,做相應操作。

管理資源部分:

  1. 加載解析源代碼。
  2. 管理所有的協程:每次執行生成一個新的協程去執行。
  3. 管理對象生命周期:垃圾回收,對象池什么的。

變量棧

lua內部函數調用和外部函數調用,都依賴棧來傳遞參數和返回值。
傳遞參數時,參數緊跟函數對象壓入棧中,通過棧頂位置和函數對象位置可以知道參數了哪些參數。
傳遞返回值時,內部函數調用和外部擴展函數調用的處理是不一樣的。

  1. lua內部函數的return命令負責把返回值copy到函數對象的位置,并重新設置棧頂。
  2. 外部函數將返回參數壓入棧頂,通過返回值告訴lua返回值數量,lua的調用模塊負責復制copy返回值到函數對象所在的位置。

閉包實現

現在的腳本語言都支持閉包,并且使用的相當自然,程序員可能都沒有察覺。

function test_closure()
   -- 這個num被Add和Print捕捉成閉包變量,生命周期延長了    
   local num = 0
    local function Add()
        num = num + 1
    end
    local function Print()
        print(num)
    end
    return Add, Print
end

local Add,Print = test_closure()
Print() -- 0
Add()
Print() -- 1

閉包變量可以理解成子函數保存了父級函數的局部變量的指針。
閉包本身可以當成運行時函數,包含函數定義和運行環境變量兩部分

一種實現:閉包變量作為一個特殊對象分兩種狀態:

  1. 新建閉包時new一批閉包變量,是個指針容器,指向棧上的局部變量,出入開狀態。
  2. 當局部變量回收時,閉包變量copy局部變量,進入閉狀態。
    (luna的閉包實現想討巧,去掉開閉狀態維護,然而有bug)

協程

lua支持協程,核心點是lua支持中斷當前協程的執行,等待后續恢復執行。中斷協程的執行需要保存當前所有函數調用信息,一個函數調用可以理解成一個函數幀
存在一個問題:c->lua->c->lua(yield),中間插入了一次c調用,中斷協程時lua是沒有辦法保存c的狀態的。
故而lua提供了lua_callk函數,用于處理這種情況,告訴lua這層c函數幀可以不保存??梢岳斫獬晌舱{用,當前函數幀可以忽略掉。

oms的處理是,每次調用,都是開一個新的協程去執行,不存在插入外部函數幀的問題。(寫oms的原因之一就是想試試這種方法)
一些想法:

  1. 同步式的寫代碼:腳本本身對與被中斷無感知,比如讀取數據庫,不需要回調函數去處理。
  2. 中斷方負責協程的繼續執行。

垃圾回收

lua是用的標記掃描的方式來回收的,實現簡單,還可以實現整理碎片內存的功能。

oms偷懶了,用C#之類的帶垃圾回收的語言實現,也就不需要再加一層垃圾回收了。
但是有個缺點,不好實現對象內存池。內存池的回收接口調用有問題,只能等C#回收對象是,調用析構函數處理了。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容