Lua

lua_State和global_state

分析Lua5.3.4源码,创建一个 Lua 状态机

Posted by Bob on July 27, 2018

分析Lua5.3.4源码,创建一个 Lua 状态机

luaL_newstate对用户的包装

/*lauxlib.c*/
LUALIB_API lua_State *luaL_newstate (void) {
  lua_State *L = lua_newstate(l_alloc, NULL);
  if (L) lua_atpanic(L, &panic);
  return L;
}

lua_newstate:创建一个新的 Lua 状态机.

lua_newstate 接受2个参数,一个类型是lua_Alloc,另一个是void 。 f_luaopen调用stack_init初始化栈大小,默认为2LUA_MINSTACK,即 2* 20 = 40。 最后返回lua_State* L。

/*lstate.c*/
LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
  int i;
  lua_State *L;/*'per thread' state*/
  global_State *g;/*'global state', shared by all threads of this state*/
  LG *l = cast(LG *, (*f)(ud, NULL, LUA_TTHREAD, sizeof(LG)));
  if (l == NULL) return NULL;
  L = &l->l.l;
  g = &l->g;
  ...
  if (luaD_rawrunprotected(L, f_luaopen, NULL) != LUA_OK) {
    /* memory allocation error: free partial state */
    close_state(L);
    L = NULL;
  }
  return L;
}

Lua 状态机中使用的内存分配器函数l_alloc :

C函数库中的malloc和free分别用于执行动态内存分配和释放,在stdlib.h中声明。

void *malloc ( size_t size );

malloc的作用是在堆内存的动态存储区中分配一个长度为size的连续空间,其参数是一个无符号整形数,返回值是一个指向所分配的连续存储域的起始地址的指针。

void free ( void *pointer );

由于堆内存区域是有限的,不能不限制地分配下去,而且一个程序要尽量节省资源,所以当所分配的内存区域不用时,就要释放它,以便其它的变量或者程序使用。这时就要用到free函数。

void *realloc (void *ptr, size_t new_size );

realloc函数用于修改一个原先已经分配的内存块(malloc )的大小,可以使一块内存的扩大或缩小。当起始空间的地址为空,即*ptr = NULL,则同malloc

/*lauxlib.c*/
static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
  (void)ud; (void)osize;  /* not used */
  if (nsize == 0) {
    free(ptr);
    return NULL;
  }
  else
    return realloc(ptr, nsize);
}

lua_newstate第一块申请的内存将用来存储global_State(全局状态机)和lua_State(主线程)实例。为了避免内存碎片的产生,利用一个LG结构,把分配lua_State和global_State的行为关联在一起。 image

/*
@@ LUA_EXTRASPACE defines the size of a raw memory area associated with
** a Lua state with very fast access.
** CHANGE it if you need a different size.
*/
#define LUA_EXTRASPACE		(sizeof(void *))

/*
** thread state + extra space
*/
typedef struct LX {
  lu_byte extra_[LUA_EXTRASPACE];
  lua_State l;
} LX;
/*
** Main thread combines a thread state and the global state
*/
typedef struct LG {
  LX l;
  global_State g; 
} LG;

image

global_State:管理lua虚拟机的全局环境,global_state 是不可见的。

1.stringtable:全局字符串表, 字符串池化,使得整个虚拟机中短字符串只有一份实例。

2.gc相关的信息

3.l_registry : 注册表(管理全局数据) ,Registry表可以用debug.getregistry获取。注册表
就是一个全局的table(即整个虚拟机中只有一个注册表),它只能被C代码访问,通常,它用来保存
那些需要在几个模块中共享的数据。比如通过luaL_newmetatable创建的元表就是放在全局的注册表中。

4.主lua_State, 在一个独立的lua虚拟机里, global_State是一个全局的结构,
 而lua_State可以有多个。 lua_newstate会创建出一个lua_State, 绑在
 lua_State *mainthread.可以说是主线程、主执行栈。

 

5.Meta table :tmname (tag method name) 预定义了元方法名字数组;mt 每一个Lua 的基本数
据类型都有一个元表。 global_mt可以用debug.getmetatable获取。

lua_State:管理一个lua虚拟机的上下文执行环境,也指代 lua 的一个线程。 一个lua虚拟机可以有多个执行环境.所有的lua C API 都是围绕这个状态机。它暴露给用户使用。

1.stack的管理, 包括管理整个栈和当前函数使用的栈的情况.每个线程拥有独立的数据栈以及函数调用栈。

2.CallInfo的管理

3.hook相关、错误处理设置

4.gc相关的信息

资料手册: Lua 5.3 参考手册