Lua虚拟机的初始化

一、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的源码:

[cpp]  view plain  copy
  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.   
  9. // lstate.c  
  10. /* 
  11. ** thread state + extra space 
  12. */  
  13. typedef struct LX {  
  14.   lu_byte extra_[LUA_EXTRASPACE];  
  15.   lua_State l;  
  16. } LX;  
  17.   
  18. /* 
  19. ** Main thread combines a thread state and the global state 
  20. */  
  21. typedef struct LG {  
  22.   LX l;  
  23.   global_State g;  
  24. } LG;  
  25.   
  26. // lstate.c  
  27. LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {  
  28.   int i;  
  29.   lua_State *L;  
  30.   global_State *g;  
  31.   LG *l = cast(LG *, (*f)(ud, NULL, LUA_TTHREAD, sizeof(LG)));  
  32.   if (l == NULL) return NULL;  
  33.   L = &l->l.l;  
  34.   g = &l->g;  
  35.   ......  
  36.   return L;  
  37. }  

可见,通过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传进来的内存分配器分配


OK,这篇文章主要是借lua_newstate讲述global_State和lua_State的结构与作用,希望对大家了解Lua工作环境有一点帮助。

下一篇将讲述Lua栈相关的内容,更新中。。。


参考文献:

http://www.cnblogs.com/ringofthec/archive/2010/11/09/lua_State.html

http://blog.csdn.net/maximuszhou/article/details/46277695

猜你喜欢

转载自blog.csdn.net/zhongdong00/article/details/80235291