为什么内部 Lua 字符串存储的方式是这样的?
我想要一个简单的字符串表,可以存储一堆常量,我想“嘿!Lua可以做到,让我使用一些它们的函数!”
这主要是在lstring.h/lstring.c文件中(我正在使用5.2)
我首先会展示我感兴趣的代码。它来自lobject.h
/*
** Header for string value; string bytes follow the end of this structure
*/
typedef union TString {
L_Umaxalign dummy; /* ensures maximum alignment for strings */
struct {
CommonHeader;
lu_byte reserved;
unsigned int hash;
size_t len; /* number of characters in string */
} tsv;
} TString;
/* get the actual string (array of bytes) from a TString */
#define getstr(ts) cast(const char *, (ts) + 1)
/* get the actual string (array of bytes) from a Lua value */
#define svalue(o) getstr(rawtsvalue(o))
正如你所看到的,数据存储在结构外部。要获取字节流,需要获取TString的大小,加1,然后获得char*指针。
但这不是糟糕的编码吗?在我的C类中,已经强调了明确定义的结构。我知道我可能会触碰到敏感话题,但将一个结构定义为数据的标头而不是定义一个指针值来容纳该数据,你真的会失去那么多速度/空间吗?
原文链接 https://stackoverflow.com/questions/8979999
正如 Rodrigo 所说,思路是将标题和字符串数据作为单个内存块进行分配。值得指出的是,您还可以看到非标准的 hack
struct lenstring {
unsigned length;
char data[0];
};
但是 C99 中添加了灵活的数组成员,所以可以以符合标准的方式完成,如下所示
struct lenstring {
unsigned length;
char data[];
};
如果 Lua 的字符串是这样做的,它会是这样的
typedef union TString {
L_Umaxalign dummy;
struct {
CommonHeader;
lu_byte reserved;
unsigned int hash;
size_t len;
const char data[];
} tsv;
} TString;
#define getstr(ts) (ts->tsv->data)
这与C语言的限制有关。在C++中,你只需要定义一个名为 GCObject
的基类,其中包含垃圾回收变量,然后 TString
就是一个子类,并使用虚析构函数,即可正确释放 TString
和其附带的 const char *
块。
C语言中编写相同功能的代码要困难一些,因为类和虚继承在C中不存在。
Lua实现垃圾回收的方法是插入所需的头来管理其后面的内存块的垃圾回收状态。请记住,free(void*)
不需要知道除内存块地址外的任何信息。
#define CommonHeader GCObject *next; lu_byte tt; lu_byte marked
Lua将这些 "collectable" 内存块的链表保留在内存中,以便可以有效地释放内存,而无需知道指向的对象类型。
如果 TString
指向另一个内存块,该内存块包含字符数组,则需要垃圾收集器确定对象的类型,然后深入其结构以 _同时_释放字符串缓冲区。
这种垃圾回收的伪代码如下:
GCHeader *next, *prev;
GCHeader *current = firstObject;
while(current)
{
next = current->next;
if (/* current is ready for deletion */)
{
free(current);
// relink previous to the next (singly-linked list)
if (prev)
prev->next = next;
}
else
prev = current; // store previous undeleted object
current = next;
}
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?
- addEventListener 返回 nil Lua
- Lua中获取用户配置主目录的跨平台方法
- 如何编写 Lua 模式将字符串(嵌套数组)转换为真正的数组?
这里的想法可能是:您可以将标题和数据分配在一个大块数据中,而不是两个块中:
TString *str = (TString*)malloc(sizeof(TString) + <length_of_string>);
除了只调用一次malloc/free之外,还可以减少内存碎片化并增加内存本地化。但是,回答您的问题,是的,这种hack通常是不好的习惯,应该非常小心地处理。如果您这样做,您可能会希望通过宏/内联函数隐藏它们。