/* ** Common type for all collectable objects */ typedefstructGCObjectGCObject;
/* ** Common Header for all collectable objects (in macro form, to be ** included in other objects) */ #define CommonHeader GCObject *next; lu_byte tt; lu_byte marked
/* ** Common type has only the common header */ structGCObject { CommonHeader; };
/* ** Header for string value; string bytes follow the end of this structure ** (aligned according to 'UTString'; see next). */ typedefstructTString { CommonHeader; lu_byte extra; /* reserved words for short strings; "has hash" for longs */ lu_byte shrlen; /* length for short strings */ unsignedint hash; union { size_t lnglen; /* length for long strings */ structTString *hnext;/* linked list for hash table */ } u; } TString;
为确保内存对齐使用结构体UTString又套了一层:
1 2 3 4 5 6 7
/* ** Ensures that address after this type is always fully aligned. */ typedefunion UTString { L_Umaxalign dummy; /* ensures maximum alignment for strings */ TString tsv; } UTString;
在lstring.c中有创建字符串的函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/* ** creates a new string object */ static TString *createstrobj(lua_State *L, size_t l, int tag, unsignedint h){ TString *ts; GCObject *o; size_t totalsize; /* total size of TString object */ totalsize = sizelstring(l); o = luaC_newobj(L, tag, totalsize); ts = gco2ts(o); ts->hash = h; ts->extra = 0; getstr(ts)[l] = '\0'; /* ending 0 */ return ts; }
/* ** Get the actual string (array of bytes) from a 'TString'. ** (Access to 'extra' ensures that value is really a 'TString'.) */ #define getstr(ts) \ check_exp(sizeof((ts)->extra), cast(char *, (ts)) + sizeof(UTString))
/* get the actual string (array of bytes) from a Lua value */ #define svalue(o) getstr(tsvalue(o))
短字符串和长字符串
执行下边的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
collectgarbage("collect") collectgarbage("stop")
-- ------------------------------------------------------- local before = collectgarbage("count")
local s1 = "1234567890123456789012345678901234567890"-- 长度 40 -- local s1 = "123456789012345678901234567890123456789" -- 长度 39
/* Variant tags for strings */ #define LUA_TSHRSTR (LUA_TSTRING | (0 << 4)) /* short strings */ #define LUA_TLNGSTR (LUA_TSTRING | (1 << 4)) /* long strings */
短字符串的最大长度为40,定义于llimits.h:
1 2 3 4 5 6 7 8 9
/* ** Maximum length for short strings, that is, strings that are ** internalized. (Cannot be smaller than reserved words or tags for ** metamethods, as these strings must be internalized; ** #("function") = 8, #("__newindex") = 10.) */ #if !defined(LUAI_MAXSHORTLEN) #define LUAI_MAXSHORTLEN 40 #endif
collectgarbage("collect") collectgarbage("stop") local before = collectgarbage("count") -- -------------------------------------------------------
local a = {}
-- ------------------------------------------------------- local after = collectgarbage("count") print(1024 * (after - before))
得到的结果是56个字节,一个空表的内存占用。
结构和定义
表的类型定于与lobject.h第497行:
1 2 3 4 5 6 7 8 9 10 11
typedef struct Table { CommonHeader; lu_byte flags; /* 1<<p means tagmethod(p) is not present */ lu_byte lsizenode; /* log2 of size of 'node' array */ unsigned int sizearray; /* size of 'array' array */ TValue *array; /* array part */ Node *node; Node *lastfree; /* any free position is before this position */ struct Table *metatable; GCObject *gclist; } Table;
static lua_Unsigned unbound_search(Table *t, lua_Unsigned j){ lua_Unsigned i = j; /* i is zero or a present index */ j++; /* find 'i' and 'j' such that i is present and j is not */ while (!ttisnil(luaH_getint(t, j))) { i = j; if (j > l_castS2U(LUA_MAXINTEGER) / 2) { /* overflow? */ /* table was built with bad purposes: resort to linear search */ i = 1; while (!ttisnil(luaH_getint(t, i))) i++; return i - 1; } j *= 2; } /* now do a binary search between them */ while (j - i > 1) { lua_Unsigned m = (i+j)/2; if (ttisnil(luaH_getint(t, m))) j = m; else i = m; } return i; }
/* ** Try to find a boundary in table 't'. A 'boundary' is an integer index ** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil). */ lua_Unsigned luaH_getn(Table *t){ unsignedint j = t->sizearray; if (j > 0 && ttisnil(&t->array[j - 1])) { /* there is a boundary in the array part: (binary) search for it */ unsignedint i = 0; while (j - i > 1) { unsignedint m = (i+j)/2; if (ttisnil(&t->array[m - 1])) j = m; else i = m; } return i; } /* else must find a boundary in hash part */ elseif (isdummy(t)) /* hash part is empty? */ return j; /* that is easy... */ elsereturn unbound_search(t, j); }
/* ** nums[i] = number of keys 'k' where 2^(i - 1) < k <= 2^i */ staticvoidrehash(lua_State *L, Table *t, const TValue *ek){ unsignedint asize; /* optimal size for array part */ unsignedint na; /* number of keys in the array part */ unsignedint nums[MAXABITS + 1]; int i; int totaluse; for (i = 0; i <= MAXABITS; i++) nums[i] = 0; /* reset counts */ na = numusearray(t, nums); /* count keys in array part */ totaluse = na; /* all those keys are integer keys */ totaluse += numusehash(t, nums, &na); /* count keys in hash part */ /* count extra key */ na += countint(ek, nums); totaluse++; /* compute new size for array part */ asize = computesizes(nums, &na); /* resize the table to new computed sizes */ luaH_resize(L, t, asize, totaluse - na); }
/* ** Count keys in array part of table 't': Fill 'nums[i]' with ** number of keys that will go into corresponding slice and return ** total number of non-nil keys. */ staticunsignedintnumusearray(const Table *t, unsignedint *nums){ int lg; unsignedint ttlg; /* 2^lg */ unsignedint ause = 0; /* summation of 'nums' */ unsignedint i = 1; /* count to traverse all array keys */ /* traverse each slice */ for (lg = 0, ttlg = 1; lg <= MAXABITS; lg++, ttlg *= 2) { unsignedint lc = 0; /* counter */ unsignedint lim = ttlg; if (lim > t->sizearray) { lim = t->sizearray; /* adjust upper limit */ if (i > lim) break; /* no more elements to count */ } /* count elements in range (2^(lg - 1), 2^lg] */ for (; i <= lim; i++) { if (!ttisnil(&t->array[i-1])) lc++; } nums[lg] += lc; ause += lc; } return ause; }
staticintnumusehash(const Table *t, unsignedint *nums, unsignedint *pna){ int totaluse = 0; /* total number of elements */ int ause = 0; /* elements added to 'nums' (can go to array part) */ int i = sizenode(t); while (i--) { Node *n = &t->node[i]; if (!ttisnil(gval(n))) { ause += countint(gkey(n), nums); totaluse++; } } *pna += ause; return totaluse; }
intluaH_next(lua_State *L, Table *t, StkId key){ unsignedint i = findindex(L, t, key); /* find original element */ for (; i < t->sizearray; i++) { /* try first array part */ if (!ttisnil(&t->array[i])) { /* a non-nil value? */ setivalue(key, i + 1); setobj2s(L, key+1, &t->array[i]); return1; } } for (i -= t->sizearray; cast_int(i) < sizenode(t); i++) { /* hash part */ if (!ttisnil(gval(gnode(t, i)))) { /* a non-nil value? */ setobj2s(L, key, gkey(gnode(t, i))); setobj2s(L, key+1, gval(gnode(t, i))); return1; } } return0; /* no more elements */ }
/* ** Function Prototypes */ typedefstructProto { CommonHeader; lu_byte numparams; /* number of fixed parameters */ lu_byte is_vararg; lu_byte maxstacksize; /* number of registers needed by this function */ int sizeupvalues; /* size of 'upvalues' */ int sizek; /* size of 'k' */ int sizecode; int sizelineinfo; int sizep; /* size of 'p' */ int sizelocvars; int linedefined; /* debug information */ int lastlinedefined; /* debug information */ TValue *k; /* constants used by the function */ Instruction *code; /* opcodes */ structProto **p;/* functions defined inside the function */ int *lineinfo; /* map from opcodes to source lines (debug information) */ LocVar *locvars; /* information about local variables (debug information) */ Upvaldesc *upvalues; /* upvalue information */ structLClosure *cache;/* last-created closure with this prototype */ TString *source; /* used for debug information */ GCObject *gclist; } Proto;
/* ** Upvalues for Lua closures */ structUpVal { TValue *v; /* points to stack or to its own value */ lu_mem refcount; /* reference counter */ union { struct {/* (when open) */ UpVal *next; /* linked list */ int touched; /* mark to avoid cycles with dead threads */ } open; TValue value; /* the value (when closed) */ } u; };
/* Find variable with given name 'n'. If it is an upvalue, add this upvalue into all intermediate functions. */ staticvoidsinglevaraux(FuncState *fs, TString *n, expdesc *var, int base){ if (fs == NULL) /* no more levels? */ init_exp(var, VVOID, 0); /* default is global */ else { int v = searchvar(fs, n); /* look up locals at current level */ if (v >= 0) { /* found? */ init_exp(var, VLOCAL, v); /* variable is local */ if (!base) markupval(fs, v); /* local will be used as an upval */ } else { /* not found as local at current level; try upvalues */ int idx = searchupvalue(fs, n); /* try existing upvalues */ if (idx < 0) { /* not found? */ singlevaraux(fs->prev, n, var, 0); /* try upper levels */ if (var->k == VVOID) /* not found? */ return; /* it is a global */ /* else was LOCAL or UPVAL */ idx = newupvalue(fs, n, var); /* will be a new upvalue */ } init_exp(var, VUPVAL, idx); /* new or old upvalue */ } } }