lua内存管理
本篇文章主要探讨 Lua 中的内存管理,涉及到的文件有 lmem.c 和 lauxlib.c。
Lua 内存管理概述
众所周知,Lua 是用纯 C 语言编写的,因此 Lua 中的内存管理本质上是采用 C 语言的方式来进行的。
关于 frealloc 函数
/*
** About the realloc function:
** void * frealloc (void *ud, void *ptr, size_t osize, size_t nsize);
** (`osize’ is the old size, `nsize’ is the new size)
**
** Lua ensures that (ptr == NULL) iff (osize == 0).
**
** * frealloc(ud, NULL, 0, x) creates a new block of size `x’
**
** * frealloc(ud, p, x, 0) frees the block `p’
** (in this specific case, frealloc must return NULL).
** particularly, frealloc(ud, NULL, 0, 0) does nothing
** (which is equivalent to free(NULL) in ANSI C)
**
** frealloc returns NULL if it cannot create or reallocate the area
** (any reallocation to an equal or smaller size cannot fail!)
*/
从注释中可以清晰地了解到,Lua 使用 void * frealloc (void *ud, void *ptr, size_t osize, size_t nsize); 接口来进行内存的释放和分配操作。该接口将内存的释放和分配操作整合在同一个函数中,既可以只进行释放操作,也可以只进行分配操作,还可以同时进行释放和分配操作。
源码分析
/*
** generic allocation routine.
*/
void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) {
global_State *g = G(L);
block = (*g->frealloc)(g->ud, block, osize, nsize);
g->totalbytes = (g->totalbytes - osize) + nsize;
return block;
}
为了便于代码分析,我们去掉源码中的断言。具体分析如下:
global_State *g = G(L);:通过当前栈指针L获得全局栈指针g。栈指针以及全局栈指针的详细说明将在后续文章中展开。block = (*g->frealloc)(g->ud, block, osize, nsize);:通过frealloc接口释放block指针指向的大小为osize的内存,并申请大小为nsize的内存,最后让block指针指向新申请的内存。这里将需要释放的内存和新申请的内存使用同一个指针来管理。g->totalbytes = (g->totalbytes - osize) + nsize;:刷新全局内存计数,确保对 Lua 中使用的总内存量进行准确记录。return block;:返回指向新申请内存的指针。
此外,内存管理的其他宏定义,如 luaM_reallocv、luaM_freemem、luaM_free、luaM_malloc、luaM_new 等,实际上只是对 luaM_realloc_ 接口进行了再次封装,理解起来相对容易。
frealloc 的实现细节
在前面的分析中,我们只知道使用 frealloc 接口来进行内存的释放和分配操作,下面我们来深入了解它的具体实现。
static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
(void)ud;
(void)osize;
if (nsize == 0) {
free(ptr);
return NULL;
}
else
return realloc(ptr, nsize);
}
这段代码非常简洁明了。当 nsize 等于 0 时,表示只需要释放 ptr 指向的内存,此时调用 C 标准库中的 free 函数进行释放操作,并返回 NULL。反之,如果 nsize 不为 0,则调用 realloc 函数对 ptr 指向的内存进行重新分配。free 和 realloc 都是 C 语言标准库提供的内存操作 API。