以下源码基于lua-5.4.8
在了解TValue之前,我们要先知道lua的一些基本数据类型
// lobject.h
/*
** basic types
*/
#define LUA_TNONE (-1) //表示“无类型”或“未定义类型”。
#define LUA_TNIL 0 //表示nil值
#define LUA_TBOOLEAN 1 //bool值,lua里面0也是真值
#define LUA_TLIGHTUSERDATA 2 //轻量级void*,其内存释放管理由外部传入者负责例如C指针
#define LUA_TNUMBER 3 //数字类型
#define LUA_TSTRING 4 //字符串类型
#define LUA_TTABLE 5 //表类型
#define LUA_TFUNCTION 6 //函数类型
#define LUA_TUSERDATA 7 //void*,内存由luaGC管理,有自己的元表
#define LUA_TTHREAD 8 //协程类型
#define LUA_NUMTYPES 9 //定义基本类型总数Lua是有一套自己的gc管理内存的,除了 LUA_TNIL,LUA_TBOOLEAN,LUA_TLIGHTUSERDATA,LUA_TNUMBER 基本上都是可GC的,那么Lua是怎么知道特定类型可GC或者让特定类型可GC的?
请看以下TValue相关源码
Value 是Lua内部用来表示所有可能的值的一个联合体。Lua是一种动态类型语言,它的变量可以随时改变类型,比如从数字变为字符串、表等。为了在内部高效地表示这些值,Lua使用了一个联合体 Value 来存储所有可能的数据类型,同时TValue配合一个“类型标签”(tt_)来标识当前存储的具体是什么类型.在Lua中的任何数据都可以通过该结构体进行表示.
// lobject.h
/*
** Union of all Lua values
*/
typedef union Value {
struct GCObject *gc; /* 指向可垃圾回收对象,如 TString, Table 等 */
/*下面都是不可回收数据类型*/
void *p; /* 指向轻量级用户数据 */
lua_CFunction f; /* 指向 C 函数 */
lua_Integer i; /* 整数类型 */
lua_Number n; /* 浮点数类型 */
lu_byte ub; /* 未使用,避免警告 */
} Value;
/*
** Tagged Value:一个 Lua 值 = 一个值(value_) + 一个类型标记(tt_)
*/
/*
** TValue 的类型标记(tt_)是一个 8-bit 数字
** bits 0-3: 表示 实际的类型值(type tag)
** bits 4-5: 表示 变体(variant bits)
** bit 6: 表示该值是否为 可垃圾回收对象
*/
#define TValuefields Value value_; lu_byte tt_
typedef struct TValue {
TValuefields;
} TValue;
/*
** 所有可垃圾回收对象的公共头部(用宏定义,会被包含进具体对象中)
** next 指针 指向下一个GC对象
** tt GC对象的实际类型(比如上面6中GC对象)
** marked 标识GC的状态
*/
#define CommonHeader struct GCObject *next; lu_byte tt; lu_byte marked
/*
** 所有可垃圾回收对象的基类(结构体)
*/
typedef struct GCObject {
CommonHeader;
} GCObject;
/*
** Header for a string value.
*/
typedef struct TString {
CommonHeader; //示例对象,包含了CommandHeader这个结构体对象
lu_byte extra; /* 用于短字符串的保留字段;对长字符串可能表示 "has hash" */
lu_byte shrlen; /* 短字符串的长度,如果是长字符串则为 0xFF */
unsigned int hash;
union {
size_t lnglen; /* 长字符串的长度 */
struct TString *hnext; /* 哈希冲突时,链表指针 */
} u;
char contents[1]; /* 字符串内容(柔性数组,实际字符串紧接其后) */
} TString;
任何需要gc的Lua数据类型,必然以CommonHeader做为该结构体定义的最开始部分.熟悉C++的人,可以将CommonHeader这个成员理解为一个基类的所有成员,需要gc的数据类型都会继承Command这个类,而C语言中一个结构体通过包含另一个结构体的指针或者直接嵌入另一个结构体(一般作为第一个成员),可以简单模拟继承关系。
为此所有可GC的对象都会包含CommonHeader作为开头视为GCObject的子类,也就意味着它是被垃圾回收模块所管理的。
当Lua创造一个可GC对象时(以TString为例),TValue的TValue.tt_ 被设为 ctb(LUA_TSTRING),其 value_.gc 字段指向一个TString,而该对象也将以 CommonHeader 开头,作为 GCObject 的子类而被视为可GC了

参考文章:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。