在lua中设置不同的内存分配函数

时间:2013-12-20 18:35:21

标签: c memory-management lua

我正在做Roberto Ierusalimschy的第三版“Lua编程”一书中的练习。我的练习32.1的解决方案中存在一个问题。该声明在代码中作为注释提供。

/*
  Exercise 32.1:
    Write a library that allows a script to limit the total amount of memory
used by its Lua state. It may offer a single function, setlimit, to set that
limit.
    The library should set its own allocation funciton. This function, before
calling the original allocator, checks the total memory in use and returns
NULL if the requested memory exeeds the limit.
    (Hint: the library can use lua_gc to initialize its byte count when it
starts. It also can use the user data of the allocation function to keep its
state: the byte count, the current memory limit, etc.; remember to use the
original user data when calling the original allocation function.)
*/

#ifdef WIN32
  #define LUA_EXPORT __declspec(dllexport)
#else
  #define LUA_EXPORT
#endif

#include <lauxlib.h>

typedef struct MemLimitUData
{
  size_t mem_limit;
  size_t currently_used;
  lua_Alloc original_alloc;
  void *original_ud;
}
MemLimitUData;

static int l_setlimit(lua_State *L)
{
  MemLimitUData *ud;
  size_t mem_limit = luaL_checkinteger(L, 1);

  lua_getallocf(L, &ud);
  ud->mem_limit = mem_limit;

  return 0;
}

static int l_getlimit(lua_State *L)
{
  MemLimitUData *ud;

  lua_getallocf(L, &ud);
  lua_pushnumber(L, ud->mem_limit);

  return 1;
}

static void *l_alloc(void *ud, void *ptr, size_t osize, size_t nsize)
{
  MemLimitUData *udata = (MemLimitUData*)ud;

  if (udata->mem_limit != 0 &&
      udata->mem_limit < udata->currently_used - osize + nsize)
  {
    return NULL;
  }

  udata->currently_used += nsize - osize;
  return udata->original_alloc(udata->original_ud, ptr, osize, nsize);
}

static const luaL_Reg memlimit[] =
{
  { "setlimit", l_setlimit },
  { "getlimit", l_getlimit },
  { NULL, NULL }
};

int LUA_EXPORT luaopen_memlimit(lua_State *L)
{
  MemLimitUData *ud =
    (MemLimitUData*)lua_newuserdata(L, sizeof(MemLimitUData));

  ud->mem_limit = 0;
  ud->currently_used =
    lua_gc(L, LUA_GCCOUNT, 0) * 1024 + lua_gc(L, LUA_GCCOUNTB, 0);
  ud->original_alloc = lua_getallocf(L, &ud->original_ud);

  lua_setallocf(L, l_alloc, ud);
  luaL_newlib(L, memlimit);

  return 1;
}

当我将源代码构建为 memlimit.dll 并从Lua脚本中使用它时,

local memlimit = require"memlimit"
程序在脚本结束时崩溃。当我使用调试器来查找问题时,有问题的语句似乎在Lua内部。该文件是 lmem.c 84

newblock = (*g->frealloc)(g->ud, block, osize, nsize);

Lua的使用版本是5.2.3。

我打破Lua内存管理有什么问题?

1 个答案:

答案 0 :(得分:2)

我还没有尝试过你的代码,但是当我阅读它时,这引起了我的注意:

ud中的luaopen_memlimit创建为userdata,但未锚定在Lua中。将其传递给lua_getallocf并不算作锚定。当程序在尝试使用您的ud释放所有数据时,lua_close结束时,可能会收集l_alloc。您应该使用普通malloc或原始的allocf来创建ud