Lua点滴程序员Lua

lua 5.3.4 GC的变化-UpVal变为引用计数管理

2017-09-29  本文已影响72人  云木unity

Lua 5.1.4

/*
** Upvalues
*/

typedef struct UpVal {
  CommonHeader;
  TValue *v;  /* points to stack or to its own value */
  union {
    TValue value;  /* the value (when closed) */
    struct {  /* double linked list (when open) */
      struct UpVal *prev;
      struct UpVal *next;
    } l;
  } u;
} UpVal;


/*
** `global state', shared by all threads of this state
*/

typedef struct global_State {
    ...
    UpVal uvhead;  /* head of double-linked list of all open upvalues */
    ...
} global_State;


/*
** `per thread' state
*/
struct lua_State {
    ...
    GCObject *openupval;  /* list of open upvalues in this stack */
    ...
};

Lua 5.3.4

/*
** Upvalues for Lua closures
*/
struct UpVal {
  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;
};

/*
** 'global state', shared by all threads of this state
*/
typedef struct global_State {
    ...
    struct lua_State *twups;  /* list of threads with open upvalues */
    ...
} global_State;


/*
** `per thread' state
*/
struct lua_State {
    ...
    UpVal *openupval;  /* list of open upvalues in this stack */
    struct lua_State *twups;  /* list of threads with open upvalues */
    ...
};

UpVal 要注意的是:

  1. UpVal 结构中去掉了 GCObject 的通用 hader (CommonHeader),增加了一个引用计数器[refcount];

    使得 UpVal 对象不再作为 GC 对象被虚拟机的 标记-清除 GC 所管理,而是成为单独使用引用计数的方法管理的小内存块

  2. 支持双向链表的两个指针 [prev] [next] ,改为了一个指针 [next] 加上一个 [touched] 标记

  3. 去掉了g->uvhead双向链表,只留下L->openupval,并且openupval链表的类型从GCObject改为UpVal (不受标记-清除 GC 所管理)

  4. 函数执行完毕时,从 L->openupval 中去除,不再挂到`gcroot' list;

    在 free closure 对象时(freeLclosure函数),对 closure 对象 upvals 列表中的所有 UpVal 对象执行引用计数减1操作,以此来管理 UpVal 的生命周期

Lua ==5.1.4== ++luaF_close++:

void luaF_close (lua_State *L, StkId level) {
  UpVal *uv;
  ...
  while (L->openupval != NULL && (uv = ngcotouv(L->openupval))->v >= level) {
    GCObject *o = obj2gco(uv);
    ...
    L->openupval = uv->next;  /* remove from `open' list */
    if (isdead(g, o))
      luaF_freeupval(L, uv);  /* free upvalue */
    else {
      unlinkupval(uv);
      setobj(L, &uv->u.value, uv->v);
      uv->v = &uv->u.value;  /* now current value lives here */
      luaC_linkupval(L, uv);  /* link upvalue into `gcroot' list */
    }
  }
}

Lua ==5.3.4== ++luaF_close++++freeLclosure++

void luaF_close (lua_State *L, StkId level) {
  UpVal *uv;
  while (L->openupval != NULL && (uv = L->openupval)->v >= level) {
    lua_assert(upisopen(uv));
    L->openupval = uv->u.open.next;  /* remove from 'open' list */
    if (uv->refcount == 0)  /* no references? */
      luaM_free(L, uv);  /* free upvalue */
    else {
      setobj(L, &uv->u.value, uv->v);  /* move value to upvalue slot */
      uv->v = &uv->u.value;  /* now current value lives here */
      luaC_upvalbarrier(L, uv);
    }
  }
}

static void freeLclosure (lua_State *L, LClosure *cl) {
  int i;
  for (i = 0; i < cl->nupvalues; i++) {
    UpVal *uv = cl->upvals[i];
    if (uv)
      luaC_upvdeccount(L, uv);-- 引用计数减1
  }
  luaM_freemem(L, cl, sizeLclosure(cl->nupvalues));
}

-- 引用计数减1,若为0则luaM_free
void luaC_upvdeccount (lua_State *L, UpVal *uv) {
  lua_assert(uv->refcount > 0);
  uv->refcount--;
  if (uv->refcount == 0 && !upisopen(uv))
    luaM_free(L, uv);
}
  1. global_State中增加了一个 twups 链表 /* list of threads with open upvalues */

    所有带有 open upvalue 的 thread 都会放到这个链表中,这样提供了一个方便的遍历 thread 的途径,并且排除掉了没有 open upvalue 的 thread

参考:

  1. Lua设计与实现 (作者)codedump
  2. Lua upvalue 的一些实现细节
上一篇 下一篇

猜你喜欢

热点阅读