概述
lua字符串通过操作算法和内存管理,有以下优点:
- 节省内存。
- 字符串比较效率高。(比较哈希值)
问题:
- 相同的字符串共享同一份内存么?
- 相同的长字符串一定不共享同一份内存么?
- lua字符串如何管理内存?
数据结构
lua字符串TString
typedef struct TString {
CommonHeader;
lu_byte extra; /* reserved words for short strings; "has hash" for longs */
lu_byte shrlen; /* length for short strings */
unsigned int hash;
union {
size_t lnglen; /* length for long strings */
struct TString *hnext; /* linked list for hash table */
} u;
char contents[1];
} TString;
- lu_byte extra的reserved words语义是否是保留字。(保留字:local,if, …)
- char contents[1] 是存放字符串内存数据的指针。
- 与char*相比,使用char[]在struct后面一次分配内存。
全局字符串表stringtable
typedef struct stringtable {
TString **hash;
int nuse; /* number of elements */
int size;
} stringtable;
- lua会把所有字符串统一在全局的stringtable结构中管理。
- hash 使用散列表存放string。
操作算法
luaS_new 创建字符串对外接口
/*
** Create or reuse a zero-terminated string, first checking in the
** cache (using the string address as a key). The cache can contain
** only zero-terminated strings, so it is safe to use 'strcmp' to
** check hits.
*/
TString *luaS_new (lua_State *L, const char *str) {
unsigned int i = point2uint(str) % STRCACHE_N; /* hash */
int j;
TString **p = G(L)->strcache[i];
for (j = 0; j < STRCACHE_M; j++) {
if (strcmp(str, getstr(p[j])) == 0) /* hit? */
return p[j]; /* that is it */
}
/* normal route */
for (j = STRCACHE_M - 1; j > 0; j--)
p[j] = p[j - 1]; /* move out last element */
/* new element is first in the list */
p[0] = luaS_newlstr(L, str, strlen(str));
return p[0];
}
- 先在缓存中查找,命中直接返回结果,否则创建新对象并写入缓存。
- 一些文章说lua字串是全局表里的唯一对象,情况如下:
- lua5.1:不管长短串,都写入全局表和查重。
- lua5.2:只有短串写入全局表和查重。
- lua5.3&lua5.4:在lua5.2版本的基础上,先查缓存。
luaS_newlstr 创建字符串
/*
** new string (with explicit length)
*/
TString *luaS_newlstr (lua_State *L, const char *str, size_t l) {
if (l <= LUAI_MAXSHORTLEN) /* short string? */
return internshrstr(L, str, l);
else {
TString *ts;
if (unlikely(l >= (MAX_SIZE - sizeof