其实这两个基本上是一个东西的不同作用,再归结其实都是Table。这两个部分我用的少,所以经常忘,这里写个文档整理一下。
1.Registry
这是为了解决开放给Lua的C API库中保存C的非局部变量问题。
在C里面如果函数要保存持久状态,那么只能仰仗全局或者static变量,这样一来,C API库就无法同时为多个LuaState状态同时提供服务(就类似于带有static变量的C函数是不纯净的,不可重入的)。LUA本身提供了Registry来解决这个问题。其实Registry本身就是一个table,只是这个table的访问方式比较特别,需要通过一个特殊的索引子 LUA_REGISTRYINDEX 来访问。其他的操作就和一个table没有两样,这是从C API的角度看过。如果是从lua的角度看的话,Registry是完全不可见的。也就是说lua代码无法访问到registry表中的任何内容。这样做的目的,是在于防止lua代码无意中对Registry表中的内容进行更改,进而对C API产生影响。
2.References
References是在Registry基础上,为了解决在C语言中引用lua数据对象的问题而提出的解决方案。在C API中,我们永远不应该保存一个指向lua中数据对象的指针,因为lua有自己的对象生命周期管理系统,在C API中保存这个指针并不会影响对象的生命周期。但是在很多C API库中确实存在引用一个lua数据对象的需求,因此就诞生了References。References其实是通过产生一个整数来唯一的标识一个lua数据对象,并且将该对象引用在表中,这样lua的GC机制就不会影响该对象的生命周期。这个唯一整数不是随机,这个数落在这样的一个区间中: [ lua_objlen (Reference保存的目标表)+1, Reference保存的目标表的长度 + m),m是针对该表生成的Reference的总个数 。
Reference的带实现代码写的非常简洁,固定的使用Reference保存的目标表的第0个空间作为空闲链表头。空闲链表用于保存通过luaL_unref()归还的所有Reference,每次调用luaL_ref()申请新的Reference时,会首先查看空闲列表,如果空闲链表上存在有元素,则首先摘取链表头部的元素并指向下一个空闲元素。该摘下的空闲元素中被填入用户传递的lua对象,该元素的Key被作为Reference返回给调用者。当第一次调用luaL_ref()时,由于空闲链表为空,因此使用lua_objlen()获取到目标表的长度并++,作为的一个Reference。
总结一下:Reference其实就是在一个指定的表t中保存一次lua的数据对象,Refenence本身其实就是表t的索引子,简称RefIndex,当RefIndex作为Refenence时,t[RefIndex]其实就是用户要求引用的lua数据对象。当RefIndex被luaL_unref()回收时,t每一个被回收的RefIndex构成一个单向链表: t[Refindex] = Refindex0, t[Refindex0] = Refindex1, t[Refindex1] = Refindex2 ... t[0] = Refindex。
注意,t[0]始终是指向了空闲链表的头部。每次调用luaL_ref()且回收链表为空时,都会产生一个新的Reference,每次调用luaL_unref()都会销毁一个指定的Reference存入空闲链表中。
ps: Reference的实现函数luaL_ref()和luaL_unref()的实现非常精炼,数据结构的空间复用也非常高,如果是用纯C语言的话,可能会为保持
链表而单独的使用指针(当然可以使用联合体,但是这么做的人不多),但是在lua中由于不是强类型,所以直接赋值即可。
posted on 2011-05-18 17:38
无毁湖光 阅读(868)
评论(0) 编辑 收藏 引用