虚拟机

作者: 小小青蛙不怕风吹雨打 | 来源:发表于2017-03-10 17:32 被阅读0次

虚拟机分两部分:管理资源,执行指令。

执行指令部分:
协程,所有协程共享一个虚拟机。也可以理解成线程,但是同时只有一个线程正在执行。

  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#回收对象是,调用析构函数处理了。

相关文章

网友评论

      本文标题:虚拟机

      本文链接:https://www.haomeiwen.com/subject/hblogttx.html