static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { lua_State *L = (lua_State *)ud; int mode = L == NULL ? 0 : G(L)->egcmode; void *nptr; if (nsize == 0) { c_free(ptr); return NULL; } if (L != NULL && (mode & EGC_ALWAYS)) /* always collect memory if requested */ luaC_fullgc(L); if(nsize > osize && L != NULL) { #if defined(LUA_STRESS_EMERGENCY_GC) luaC_fullgc(L); #endif if(G(L)->memlimit > 0 && (mode & EGC_ON_MEM_LIMIT) && l_check_memlimit(L, nsize - osize)) return NULL; } nptr = (void *)c_realloc(ptr, nsize); if (nptr == NULL && L != NULL && (mode & EGC_ON_ALLOC_FAILURE)) { luaC_fullgc(L); /* emergency full collection. */ nptr = (void *)c_realloc(ptr, nsize); /* try allocation again */ } return nptr; }
/* ** In case of allocation fail, this function will call the GC to try ** to free some memory and then try the allocation again. ** (It should not be called when shrinking a block, because then the ** interpreter may be in the middle of a collection step.) */ static void *tryagain (lua_State *L, void *block, size_t osize, size_t nsize) { global_State *g = G(L); if (ttisnil(&g->nilvalue)) { /* is state fully build? */ luaC_fullgc(L, 1); /* try to free some memory... */ return (*g->frealloc)(g->ud, block, osize, nsize); /* try again */ } else return NULL; /* cannot free any memory without a full state */ }
/* ** generic allocation routine. */ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { void *newblock; global_State *g = G(L); size_t realosize = (block) ? osize : 0; lua_assert((realosize == 0) == (block == NULL)); #if defined(HARDMEMTESTS) if (nsize > realosize && g->gcrunning) luaC_fullgc(L, 1); /* force a GC whenever possible */ #endif newblock = (*g->frealloc)(g->ud, block, osize, nsize); if (newblock == NULL && nsize > 0) { api_check(L, nsize > realosize, "realloc cannot fail when shrinking a block"); if (g->gcrunning) { luaC_fullgc(L, 1); /* try to free some memory... */ newblock = (*g->frealloc)(g->ud, block, osize, nsize); /* try again */ } if (newblock == NULL) luaD_throw(L, LUA_ERRMEM); } lua_assert((nsize == 0) == (newblock == NULL)); g->GCdebt = (g->GCdebt + nsize) - realosize; #if defined(TRACEMEM) { /* auxiliary patch to monitor garbage collection. ** To plot, gnuplot with following command: ** plot TRACEMEM using 1:2 with lines, TRACEMEM using 1:3 with lines */ static unsigned long total = 0; /* our "time" */ static FILE *f = NULL; /* output file */ total++; /* "time" always grows */ if ((total % 200) == 0) { if (f == NULL) f = fopen(TRACEMEM, "w"); fprintf(f, "%lu %u %d %d\n", total, gettotalbytes(g), g->GCdebt, g->gcstate * 10000); } } #endif return newblock; }
/** * 调用此函数前,参数都经过检查, 保证了分配的内存块不会过大; * * 创建对象的函数 luaM_newobject 也调用此函数(lmem.h): * #define luaM_newobject(L,tag,s) luaM_realloc_(L, NULL, tag, (s)) * * nsize 为 0 表示释放内存 * #define luaM_freearray(L, b, n) luaM_realloc_(L, (b), (n)*sizeof(*(b)), 0) * * 内部调用 g->frealloc 来重新分配内存 */ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { void *newblock; global_State *g = G(L); size_t realosize = (block) ? osize : 0; lua_assert((realosize == 0) == (block == NULL)); #if defined(HARDMEMTESTS) if (nsize > realosize && g->gcrunning) luaC_fullgc(L, 1); /* force a GC whenever possible */ #endif newblock = (*g->frealloc)(g->ud, block, osize, nsize); if (newblock == NULL && nsize > 0) { api_check( nsize > realosize, "realloc cannot fail when shrinking a block"); luaC_fullgc(L, 1); /* try to free some memory... */ newblock = (*g->frealloc)(g->ud, block, osize, nsize); /* try again */ if (newblock == NULL) luaD_throw(L, LUA_ERRMEM); } lua_assert((nsize == 0) == (newblock == NULL)); g->GCdebt = (g->GCdebt + nsize) - realosize; return newblock; }
static void generationalcollection (lua_State *L) { global_State *g = G(L); if (g->lastmajormem == 0) { /* signal for another major collection? */ luaC_fullgc(L, 0); /* perform a full regular collection */ g->lastmajormem = gettotalbytes(g); /* update control */ } else { luaC_runtilstate(L, ~bitmask(GCSpause)); /* run complete cycle */ luaC_runtilstate(L, bitmask(GCSpause)); if (gettotalbytes(g) > g->lastmajormem/100 * g->gcmajorinc) g->lastmajormem = 0; /* signal for a major collection */ } luaE_setdebt(g, stddebt(g)); }
static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { lua_State *L = (lua_State *)ud; void *nptr; if (nsize == 0) { free(ptr); return NULL; } if(nsize > osize && L != NULL) { if(G(L)->memlimit > 0 && l_check_memlimit(L, nsize - osize)) return NULL; } nptr = realloc(ptr, nsize); if (nptr == NULL && L != NULL) { luaC_fullgc(L); /* emergency full collection. */ nptr = realloc(ptr, nsize); /* try allocation again */ } return nptr; }
static void generationalcollection (lua_State *L) { global_State *g = G(L); lua_assert(g->gcstate == GCSpropagate); if (g->GCestimate == 0) { /* signal for another major collection? */ luaC_fullgc(L, 0); /* perform a full regular collection */ g->GCestimate = gettotalbytes(g); /* update control */ } else { lu_mem estimate = g->GCestimate; luaC_runtilstate(L, bitmask(GCSpause)); /* run complete (minor) cycle */ g->gcstate = GCSpropagate; /* skip restart */ if (gettotalbytes(g) > (estimate / 100) * g->gcmajorinc) g->GCestimate = 0; /* signal for a major collection */ else g->GCestimate = estimate; /* keep estimate from last major coll. */ } setpause(g, gettotalbytes(g)); lua_assert(g->gcstate == GCSpropagate); }