Lua的内存管理

Lua在构建VM的时候是要求传入内存管理函数的!

/*
** Type for memory-allocation functions
*/
typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);

LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud)

说明: 需要在nsize为0的时候提供释放。 ud则是可以告知这是在哪个堆上的! 当ptr传入null时,osize的含义变成了对象的类型

一般而言,我们都不是直接使用lua_newstate去直接创建vm,而是使用

LUALIB_API lua_State *luaL_newstate (void) {
  lua_State *L = lua_newstate(l_alloc, NULL);
  if (l_likely(L)) {
    lua_atpanic(L, &panic);
    lua_setwarnf(L, warnfoff, L);  /* default is warnings off */
  }
  return L;
}
static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
  (void)ud; (void)osize;  /* not used */
  if (nsize == 0) {
    free(ptr);
    return NULL;
  }
  else
    return realloc(ptr, nsize);
}

Lua还有一组宏来管理不同类型的内存,但是最终都是找到global_state->frealloc来申请内存,global_state->frealloc就是在创建lua_newstate的时候传入的内存管理函数

lmem.h

在这些宏中,有一个比较值得注意的函数

void *luaM_growaux_ (lua_State *L, void *block, int nelems, int *psize,
                     int size_elems, int limit, const char *what) {
  void *newblock;
  int size = *psize;
  if (nelems + 1 <= size)  /* does one extra element still fit? */
    return block;  /* nothing to be done */
  if (size >= limit / 2) {  /* cannot double it? */
    if (l_unlikely(size >= limit))  /* cannot grow even a little? */
      luaG_runerror(L, "too many %s (limit is %d)", what, limit);
    size = limit;  /* still have at least one free place */
  }
  else {
    size *= 2;
    if (size < MINSIZEARRAY)
      size = MINSIZEARRAY;  /* minimum size */
  }
  lua_assert(nelems + 1 <= size && size <= limit);
  /* 'limit' ensures that multiplication will not overflow */
  newblock = luaM_saferealloc_(L, block, cast_sizet(*psize) * size_elems,
                                         cast_sizet(size) * size_elems);
  *psize = size;  /* update only when everything else is OK */
  return newblock;
}

它是用来管理可变长数组的。其主要策略是当数组空 间不够时,扩大为原来的两倍。