diff --git a/3rd/lua/lstring.c b/3rd/lua/lstring.c index c9f30fde..48102b85 100644 --- a/3rd/lua/lstring.c +++ b/3rd/lua/lstring.c @@ -218,6 +218,7 @@ struct shrmap { struct rwlock lock; int rwslots; int total; + int garbage; int roslots; struct shrmap_slot * readwrite; struct shrmap_slot * readonly; @@ -517,6 +518,14 @@ exist(struct ssm_ref *r, TString *s) { return 0; } +static void +release_tstring(TString *s) { + DEC_SREF(s); + if (ZERO_SREF(s)) { + ATOM_INC(&SSM.garbage); + } +} + static int collectref(struct collect_queue * c) { int i; @@ -535,7 +544,7 @@ collectref(struct collect_queue * c) { if (s) { if (!exist(mark, s) && !exist(fix, s)) { save->hash[i] = NULL; - DEC_SREF(s); + release_tstring(s); ++total; } } @@ -546,7 +555,7 @@ collectref(struct collect_queue * c) { if (!exist(mark, s) && !exist(fix, s)) { --save->asize; save->array[i] = save->array[save->asize]; - DEC_SREF(s); + release_tstring(s); ++total; } else { ++i; @@ -557,13 +566,13 @@ collectref(struct collect_queue * c) { for (i=0;ihsize;i++) { TString * s = save->hash[i]; if (s) { - DEC_SREF(s); + release_tstring(s); ++total; } } for (i=0;iasize;i++) { TString * s = save->array[i]; - DEC_SREF(s); + release_tstring(s); ++total; } clear_vm(c); @@ -682,6 +691,7 @@ shrstr_rehash(struct shrmap *s, int slotid) { if (ZERO_SREF(str)) { free(str); ATOM_DEC(&SSM.total); + ATOM_DEC(&SSM.garbage); } else { int newslotid = lmod(str->hash, s->rwslots); struct shrmap_slot *newslot = &s->readwrite[newslotid]; @@ -737,6 +747,63 @@ expandssm() { shrstr_deletepage(oldpage, osz); } +static int +sweep_slot(struct shrmap *s, int i) { + struct shrmap_slot *slot = &s->readwrite[i]; + int n = 0; + TString *ts; + rwlock_rlock(&slot->lock); + ts = slot->str; + while (ts) { + if (ZERO_SREF(ts)) { + n = 1; + break; + } + ts = (TString *)ts->next; + } + rwlock_runlock(&slot->lock); + if (n == 0) + return 0; + + n = 0; + rwlock_wlock(&slot->lock); + TString **ref = &slot->str; + ts = *ref; + while (ts) { + if (ZERO_SREF(ts)) { + *ref = (TString *)ts->next; + free(ts); + ts = *ref; + ATOM_DEC(&SSM.total); + ATOM_DEC(&SSM.garbage); + ++n; + } else { + ref = (TString **)&(ts->next); + ts = *ref; + } + } + rwlock_wunlock(&slot->lock); + return n; +} + +static int +sweepssm() { + struct shrmap * s = &SSM; + rwlock_rlock(&s->lock); + if (s->readonly) { + rwlock_runlock(&s->lock); + return 0; + } + int sz = s->rwslots; + int i; + int n = 0; + for (i=0;ilock); + return n; +} + /* call it in a separate thread */ LUA_API int luaS_collectssm(struct ssm_collect *info) { @@ -744,6 +811,11 @@ luaS_collectssm(struct ssm_collect *info) { if (s->total * 5 / 4 > s->rwslots) { expandssm(); } + if (s->garbage > s->total / 8) { + info->sweep = sweepssm(); + } else { + info->sweep = 0; + } if (s->head) { struct collect_queue * cqueue; spinlock_lock(&s->qlock); @@ -819,6 +891,9 @@ find_and_collect(struct shrmap_slot * slot, unsigned int h, const char *str, lu_ if (ts->hash == h && ts->shrlen == l && memcmp(str, ts+1, l) == 0) { + if (ZERO_SREF(ts)) { + ATOM_INC(&SSM.garbage); + } ADD_SREF(ts); break; } @@ -827,6 +902,7 @@ find_and_collect(struct shrmap_slot * slot, unsigned int h, const char *str, lu_ free(ts); ts = *ref; ATOM_DEC(&SSM.total); + ATOM_DEC(&SSM.garbage); } else { ref = (TString **)&(ts->next); ts = *ref; @@ -941,7 +1017,9 @@ internshrstr(lua_State *L, const char *str, size_t l) { struct slotinfo { int len; + int garbage; size_t size; + size_t garbage_size; }; static void @@ -951,7 +1029,12 @@ getslot(struct shrmap_slot *s, struct slotinfo *info) { TString *ts = s->str; while (ts) { ++info->len; - info->size += sizelstring(ts->shrlen); + size_t sz = sizelstring(ts->shrlen); + if (ZERO_SREF(ts)) { + ++info->garbage; + info->garbage_size += sz; + } + info->size += sz; ts = (TString *)ts->next; } rwlock_runlock(&s->lock); @@ -992,6 +1075,8 @@ luaS_infossm(struct ssm_info *info) { total.len = tmp.len; } total.size += tmp.size; + total.garbage_size += tmp.garbage_size; + total.garbage += tmp.garbage; variance_update(&v, tmp.len); ++slots; } @@ -1005,7 +1090,10 @@ luaS_infossm(struct ssm_info *info) { if (tmp.len > total.len) { total.len = tmp.len; } + // may double counting, but it's only an info total.size += tmp.size; + total.garbage_size += tmp.garbage_size; + total.garbage += tmp.garbage; variance_update(&v, tmp.len); } } @@ -1015,6 +1103,8 @@ luaS_infossm(struct ssm_info *info) { info->size = total.size; info->longest = total.len; info->slots = slots; + info->garbage = SSM.garbage; + info->garbage_size = total.garbage_size; if (v.count > 1) { info->variance = v.m2 / v.count; } else { diff --git a/3rd/lua/lstring.h b/3rd/lua/lstring.h index 22525adf..72ee14a0 100644 --- a/3rd/lua/lstring.h +++ b/3rd/lua/lstring.h @@ -49,13 +49,16 @@ struct ssm_info { int total; int longest; int slots; + int garbage; size_t size; + size_t garbage_size; double variance; }; struct ssm_collect { void *key; int n; + int sweep; }; LUA_API void luaS_initssm(); diff --git a/lualib-src/lua-ssm.c b/lualib-src/lua-ssm.c index 4988057d..fac37850 100644 --- a/lualib-src/lua-ssm.c +++ b/lualib-src/lua-ssm.c @@ -20,6 +20,10 @@ linfo(lua_State *L) { lua_setfield(L, -2, "slots"); lua_pushinteger(L, info.size); lua_setfield(L, -2, "size"); + lua_pushinteger(L, info.garbage); + lua_setfield(L, -2, "garbage"); + lua_pushinteger(L, info.garbage_size); + lua_setfield(L, -2, "garbage_size"); lua_pushnumber(L, info.variance); lua_setfield(L, -2, "variance"); @@ -43,6 +47,8 @@ lcollect(lua_State *L) { if (again && lua_istable(L, 2)) { lua_pushinteger(L, info.n); lua_setfield(L, 2, "n"); + lua_pushinteger(L, info.sweep); + lua_setfield(L, 2, "sweep"); lua_pushlightuserdata(L, info.key); lua_setfield(L, 2, "key"); } diff --git a/service/garbagecollect.lua b/service/garbagecollect.lua index ab19aedc..f2a00f06 100644 --- a/service/garbagecollect.lua +++ b/service/garbagecollect.lua @@ -8,10 +8,10 @@ end local function collect() local info = {} while true do - while ssm.collect(false, info) do - skynet.error(string.format("Collect %d strings from %s", info.n, info.key)) - end --- ssm.collect(true) +-- while ssm.collect(false, info) do +-- skynet.error(string.format("Collect %d strings from %s, sweep %d", info.n, info.key, info.sweep)) +-- end + ssm.collect(true) skynet.sleep(50) end end