探索Lua5.2内部实现:TString

本文介绍Lua中如何使用TString结构体管理字符串,包括短字符串和长字符串的区别,它们的存储方式及应用场景,以及如何通过哈希值提高字符串操作的效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文http://blog.youkuaiyun.com/yuanlin2008/article/details/8423923

Lua使用TString结构体代表一个字符串对象。

/*
** 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 extra;  /* reserved words for short strings; "has hash" for longs */
    unsigned int hash;
    size_t len;  /* number of characters in string */
  } tsv;
} TString;

hash用来记录字符串对应的哈希值,len用来记录字符串长度。

这个结构体其实只是字符串对象的头数据,后面紧跟着字符窜内容和一个'\0'结尾。字符串"abc"对应的TString对象应该如下图所示:


字符串对象的最终大小应该是TString的大小+字符串长度+1。

TString对应的lua对象类型为LUA_TSTRING。根据字符串长度(luaconf.h中的LUAI_MAXSHORTLEN,默认为40)的不同,TString对象还被分成两种子类型:LUA_TSHRSTR(短字符串)和LUA_TLNGSTR(长字符串)。

对于短字符串,在实际使用中一般用来作为索引或者需要进行字符串比较。不同于其他的对象,Lua并不是将其连接到全局的allgc对象链表上,而是将其放到全局状态global_State中的字符串表中进行管理。这个字符串表是一个stringtable类型的全局唯一的哈希表。当需要创建一个短字符串对象时,会首先在这个表中查找已有对象。所有的短字符串都是全局唯一的,不会存在两个相同的短字符串对象。如果需要比较两个短字符串是否相等,只需要看他们指向的是否是同一个TString对象就可以了,速度非常快。如果短字符串对象的extra > 0,表示这是一个系统保留的字符串。extra的值直接对应着词法分析时的一个token值,这样可以加速词法分析的速度。

对于长字符串,与短字符串相反,在实际使用中一般只是用来存储文本数据,很少需要比较或者索引。所以长字符串直接被挂接到allgc链表上当作普通的对象来处理。Lua不会对新创建的长字符串对象计算哈希值,也不保证长字符串对象的唯一性。当长字符串需要被用来当作索引时,会为其计算一次哈希值,并使用extra来记录是否已经为其计算了哈希值。

计算字符串的哈希值需要遍历字符串的每一个字符,如果字符串很长,会非常影响效率。对于大于等于32的字符串,Lua不会遍历每个字符,而是按照一定的间隔获取字符,最多遍历31次。这使得字符串的哈希值计算与字符串长度无关。

如果要将Lua部署到web上面来处理大量的基于文本的http请求,文本处理的安全性就变得尤为重要。为了防止Hash DoS攻击,字符串哈希值生成需要一个seed,这个seed是每次启动Lua时随机生成的。这就使不同的Lua实例对于同一个字符串会有不同的哈希值。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值