aboutsummaryrefslogtreecommitdiff
path: root/lgc.c
diff options
context:
space:
mode:
Diffstat (limited to 'lgc.c')
-rw-r--r--lgc.c190
1 files changed, 70 insertions, 120 deletions
diff --git a/lgc.c b/lgc.c
index aa95c028..1b24fda6 100644
--- a/lgc.c
+++ b/lgc.c
@@ -29,23 +29,18 @@
29 29
30 30
31/* 31/*
32** Maximum number of elements to sweep in each single step. 32** Number of fixed (luaC_fix) objects in a Lua state: metafield names,
33** (Large enough to dissipate fixed overheads but small enough 33** plus reserved words, plus "_ENV", plus the memory-error message.
34** to allow small steps for the collector.)
35*/ 34*/
36#define GCSWEEPMAX 20 35#define NFIXED (TM_N + NUM_RESERVED + 2)
37
38/*
39** Maximum number of finalizers to call in each single step.
40*/
41#define GCFINMAX 10
42 36
43 37
44/* 38/*
45** Cost of calling one finalizer. 39** Maximum number of elements to sweep in each single step.
40** (Large enough to dissipate fixed overheads but small enough
41** to allow small steps for the collector.)
46*/ 42*/
47#define GCFINALIZECOST 50 43#define GCSWEEPMAX 20
48
49 44
50 45
51/* mask with all color bits */ 46/* mask with all color bits */
@@ -205,7 +200,7 @@ void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) {
205 } 200 }
206 else { /* sweep phase */ 201 else { /* sweep phase */
207 lua_assert(issweepphase(g)); 202 lua_assert(issweepphase(g));
208 if (g->gckind == KGC_INC) /* incremental mode? */ 203 if (g->gckind != KGC_GEN) /* incremental mode? */
209 makewhite(g, o); /* mark 'o' as white to avoid other barriers */ 204 makewhite(g, o); /* mark 'o' as white to avoid other barriers */
210 } 205 }
211} 206}
@@ -398,7 +393,7 @@ static void cleargraylists (global_State *g) {
398*/ 393*/
399static void restartcollection (global_State *g) { 394static void restartcollection (global_State *g) {
400 cleargraylists(g); 395 cleargraylists(g);
401 g->marked = TM_N + NUM_RESERVED + 2; 396 g->marked = NFIXED;
402 markobject(g, g->mainthread); 397 markobject(g, g->mainthread);
403 markvalue(g, &g->l_registry); 398 markvalue(g, &g->l_registry);
404 markmt(g); 399 markmt(g);
@@ -927,17 +922,6 @@ static void GCTM (lua_State *L) {
927 922
928 923
929/* 924/*
930** Call a few finalizers
931*/
932static void runafewfinalizers (lua_State *L, int n) {
933 global_State *g = G(L);
934 int i;
935 for (i = 0; i < n && g->tobefnz; i++)
936 GCTM(L); /* call one finalizer */
937}
938
939
940/*
941** call all pending finalizers 925** call all pending finalizers
942*/ 926*/
943static void callallpendingfinalizers (lua_State *L) { 927static void callallpendingfinalizers (lua_State *L) {
@@ -1295,8 +1279,7 @@ static void atomic2gen (lua_State *L, global_State *g) {
1295 sweep2old(L, &g->tobefnz); 1279 sweep2old(L, &g->tobefnz);
1296 1280
1297 g->gckind = KGC_GEN; 1281 g->gckind = KGC_GEN;
1298 g->lastatomic = 0; 1282 g->GClastmajor = gettotalobjs(g); /* base for memory control */
1299 g->GCestimate = gettotalobjs(g); /* base for memory control */
1300 finishgencycle(L, g); 1283 finishgencycle(L, g);
1301} 1284}
1302 1285
@@ -1306,7 +1289,7 @@ static void atomic2gen (lua_State *L, global_State *g) {
1306** total number of objects grows 'genminormul'%. 1289** total number of objects grows 'genminormul'%.
1307*/ 1290*/
1308static void setminordebt (global_State *g) { 1291static void setminordebt (global_State *g) {
1309 luaE_setdebt(g, -(cast(l_obj, (gettotalobjs(g) / 100)) * g->genminormul)); 1292 luaE_setdebt(g, -(gettotalobjs(g) / 100) * g->genminormul);
1310} 1293}
1311 1294
1312 1295
@@ -1338,7 +1321,6 @@ static void enterinc (global_State *g) {
1338 g->finobjrold = g->finobjold1 = g->finobjsur = NULL; 1321 g->finobjrold = g->finobjold1 = g->finobjsur = NULL;
1339 g->gcstate = GCSpause; 1322 g->gcstate = GCSpause;
1340 g->gckind = KGC_INC; 1323 g->gckind = KGC_INC;
1341 g->lastatomic = 0;
1342} 1324}
1343 1325
1344 1326
@@ -1347,13 +1329,18 @@ static void enterinc (global_State *g) {
1347*/ 1329*/
1348void luaC_changemode (lua_State *L, int newmode) { 1330void luaC_changemode (lua_State *L, int newmode) {
1349 global_State *g = G(L); 1331 global_State *g = G(L);
1350 if (newmode != g->gckind) { 1332 if (newmode != g->gckind) { /* does it need to change? */
1351 if (newmode == KGC_GEN) /* entering generational mode? */ 1333 if (newmode == KGC_INC) { /* entering incremental mode? */
1334 if (g->gckind == KGC_GENMAJOR)
1335 g->gckind = KGC_INC; /* already incremental but in name */
1336 else
1337 enterinc(g); /* entering incremental mode */
1338 }
1339 else {
1340 lua_assert(newmode == KGC_GEN);
1352 entergen(L, g); 1341 entergen(L, g);
1353 else 1342 }
1354 enterinc(g); /* entering incremental mode */
1355 } 1343 }
1356 g->lastatomic = 0;
1357} 1344}
1358 1345
1359 1346
@@ -1367,93 +1354,52 @@ static void fullgen (lua_State *L, global_State *g) {
1367 1354
1368 1355
1369/* 1356/*
1370** Does a major collection after last collection was a "bad collection". 1357** Does a major collector up to the atomic phase and then either
1371** 1358** returns to minor collections or stays doing major ones. If the
1372** When the program is building a big structure, it allocates lots of 1359** number of objects collected this time (numobjs - marked) is more than
1373** memory but generates very little garbage. In those scenarios, 1360** half the number of objects created since the last major collection
1374** the generational mode just wastes time doing small collections, and 1361** (numobjs - lastmajor), it goes back to minor collections.
1375** major collections are frequently what we call a "bad collection", a 1362*/
1376** collection that frees too few objects. To avoid the cost of switching 1363static void genmajorstep (lua_State *L, global_State *g) {
1377** between generational mode and the incremental mode needed for full 1364 l_obj lastmajor = g->GClastmajor; /* count from last collection */
1378** (major) collections, the collector tries to stay in incremental mode 1365 l_obj numobjs = gettotalobjs(g); /* current count */
1379** after a bad collection, and to switch back to generational mode only
1380** after a "good" collection (one that traverses less than 9/8 objects
1381** of the previous one).
1382** The collector must choose whether to stay in incremental mode or to
1383** switch back to generational mode before sweeping. At this point, it
1384** does not know the real memory in use, so it cannot use memory to
1385** decide whether to return to generational mode. Instead, it uses the
1386** number of objects traversed (returned by 'atomic') as a proxy. The
1387** field 'g->lastatomic' keeps this count from the last collection.
1388** ('g->lastatomic != 0' also means that the last collection was bad.)
1389*/
1390static void stepgenfull (lua_State *L, global_State *g) {
1391 lu_mem lastatomic = g->lastatomic; /* count from last collection */
1392 if (g->gckind == KGC_GEN) /* still in generational mode? */
1393 enterinc(g); /* enter incremental mode */
1394 luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */ 1366 luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */
1395 g->marked = 0;
1396 atomic(L); /* mark everybody */ 1367 atomic(L); /* mark everybody */
1397 if (g->marked < lastatomic + (lastatomic >> 3)) { /* good collection? */ 1368 if ((numobjs - g->marked) > ((numobjs - lastmajor) >> 1)) {
1398 atomic2gen(L, g); /* return to generational mode */ 1369 atomic2gen(L, g); /* return to generational mode */
1399 setminordebt(g); 1370 setminordebt(g);
1400 } 1371 }
1401 else { /* another bad collection; stay in incremental mode */ 1372 else { /* bad collection; stay in major mode */
1402 g->GCestimate = gettotalobjs(g); /* first estimate */;
1403 g->lastatomic = g->marked;
1404 entersweep(L); 1373 entersweep(L);
1405 luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */ 1374 luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */
1406 setpause(g); 1375 setpause(g);
1376 g->GClastmajor = gettotalobjs(g);
1407 } 1377 }
1408} 1378}
1409 1379
1410 1380
1411/* 1381/*
1412** Does a generational "step". 1382** Does a generational "step". If the total number of objects grew
1413** Usually, this means doing a minor collection and setting the debt to 1383** more than 'majormul'% since the last major collection, does a
1414** make another collection when memory grows 'genminormul'% larger. 1384** major collection. Otherwise, does a minor collection. The test
1415** 1385** ('GCdebt' > 0) avoids major collections when the step originated from
1416** However, there are exceptions. If memory grows 'genmajormul'% 1386** 'collectgarbage("step")'.
1417** larger than it was at the end of the last major collection (kept
1418** in 'g->GCestimate'), the function does a major collection. At the
1419** end, it checks whether the major collection was able to free a
1420** decent amount of memory (at least half the growth in memory since
1421** previous major collection). If so, the collector keeps its state,
1422** and the next collection will probably be minor again. Otherwise,
1423** we have what we call a "bad collection". In that case, set the field
1424** 'g->lastatomic' to signal that fact, so that the next collection will
1425** go to 'stepgenfull'.
1426**
1427** 'GCdebt <= 0' means an explicit call to GC step with "size" zero;
1428** in that case, do a minor collection.
1429*/ 1387*/
1430static void genstep (lua_State *L, global_State *g) { 1388static void genstep (lua_State *L, global_State *g) {
1431 if (g->lastatomic != 0) /* last collection was a bad one? */ 1389 l_obj majorbase = g->GClastmajor; /* count after last major collection */
1432 stepgenfull(L, g); /* do a full step */ 1390 l_obj majorinc = (majorbase / 100) * getgcparam(g->genmajormul);
1433 else { 1391 if (g->GCdebt > 0 && gettotalobjs(g) > majorbase + majorinc) {
1434 l_obj majorbase = g->GCestimate; /* objects after last major collection */ 1392 /* do a major collection */
1435 l_obj majorinc = (majorbase / 100) * getgcparam(g->genmajormul); 1393 enterinc(g);
1436 if (g->GCdebt > 0 && gettotalobjs(g) > majorbase + majorinc) { 1394 g->gckind = KGC_GENMAJOR;
1437 g->marked = 0; 1395 genmajorstep(L, g);
1438 fullgen(L, g); /* do a major collection */ 1396 }
1439 if (gettotalobjs(g) < majorbase + (majorinc / 2)) { 1397 else { /* regular case; do a minor collection */
1440 /* collected at least half of object growth since last major 1398 g->marked = 0;
1441 collection; keep doing minor collections. */ 1399 youngcollection(L, g);
1442 lua_assert(g->lastatomic == 0); 1400 setminordebt(g);
1443 } 1401 lua_assert(g->GClastmajor == majorbase);
1444 else { /* bad collection */
1445 g->lastatomic = g->marked; /* signal that last collection was bad */
1446 setpause(g); /* do a long wait for next (major) collection */
1447 }
1448 }
1449 else { /* regular case; do a minor collection */
1450 g->marked = 0;
1451 youngcollection(L, g);
1452 setminordebt(g);
1453 g->GCestimate = majorbase; /* preserve base value */
1454 }
1455 } 1402 }
1456 lua_assert(isdecGCmodegen(g));
1457} 1403}
1458 1404
1459/* }====================================================== */ 1405/* }====================================================== */
@@ -1557,11 +1503,8 @@ static l_obj atomic (lua_State *L) {
1557 1503
1558static void sweepstep (lua_State *L, global_State *g, 1504static void sweepstep (lua_State *L, global_State *g,
1559 int nextstate, GCObject **nextlist) { 1505 int nextstate, GCObject **nextlist) {
1560 if (g->sweepgc) { 1506 if (g->sweepgc)
1561 l_obj olddebt = g->GCdebt;
1562 g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); 1507 g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX);
1563 g->GCestimate += g->GCdebt - olddebt; /* update estimate */
1564 }
1565 else { /* enter next state */ 1508 else { /* enter next state */
1566 g->gcstate = nextstate; 1509 g->gcstate = nextstate;
1567 g->sweepgc = nextlist; 1510 g->sweepgc = nextlist;
@@ -1618,11 +1561,11 @@ static l_obj singlestep (lua_State *L) {
1618 work = 0; 1561 work = 0;
1619 break; 1562 break;
1620 } 1563 }
1621 case GCScallfin: { /* call remaining finalizers */ 1564 case GCScallfin: { /* call finalizers */
1622 if (g->tobefnz && !g->gcemergency) { 1565 if (g->tobefnz && !g->gcemergency) {
1623 g->gcstopem = 0; /* ok collections during finalizers */ 1566 g->gcstopem = 0; /* ok collections during finalizers */
1624 runafewfinalizers(L, GCFINMAX); 1567 GCTM(L); /* call one finalizer */
1625 work = GCFINMAX * GCFINALIZECOST; 1568 work = 1;
1626 } 1569 }
1627 else { /* emergency mode or no more finalizers */ 1570 else { /* emergency mode or no more finalizers */
1628 g->gcstate = GCSpause; /* finish collection */ 1571 g->gcstate = GCSpause; /* finish collection */
@@ -1679,10 +1622,17 @@ void luaC_step (lua_State *L) {
1679 global_State *g = G(L); 1622 global_State *g = G(L);
1680 lua_assert(!g->gcemergency); 1623 lua_assert(!g->gcemergency);
1681 if (gcrunning(g)) { /* running? */ 1624 if (gcrunning(g)) { /* running? */
1682 if(isdecGCmodegen(g)) 1625 switch (g->gckind) {
1683 genstep(L, g); 1626 case KGC_INC:
1684 else 1627 incstep(L, g);
1685 incstep(L, g); 1628 break;
1629 case KGC_GEN:
1630 genstep(L, g);
1631 break;
1632 case KGC_GENMAJOR:
1633 genmajorstep(L, g);
1634 break;
1635 }
1686 } 1636 }
1687} 1637}
1688 1638
@@ -1700,7 +1650,7 @@ static void fullinc (lua_State *L, global_State *g) {
1700 /* finish any pending sweep phase to start a new cycle */ 1650 /* finish any pending sweep phase to start a new cycle */
1701 luaC_runtilstate(L, bitmask(GCSpause)); 1651 luaC_runtilstate(L, bitmask(GCSpause));
1702 luaC_runtilstate(L, bitmask(GCScallfin)); /* run up to finalizers */ 1652 luaC_runtilstate(L, bitmask(GCScallfin)); /* run up to finalizers */
1703 /* estimate must be correct after a full GC cycle */ 1653 /* 'marked' must be correct after a full GC cycle */
1704 lua_assert(g->marked == gettotalobjs(g)); 1654 lua_assert(g->marked == gettotalobjs(g));
1705 luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */ 1655 luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */
1706 setpause(g); 1656 setpause(g);
@@ -1716,10 +1666,10 @@ void luaC_fullgc (lua_State *L, int isemergency) {
1716 global_State *g = G(L); 1666 global_State *g = G(L);
1717 lua_assert(!g->gcemergency); 1667 lua_assert(!g->gcemergency);
1718 g->gcemergency = isemergency; /* set flag */ 1668 g->gcemergency = isemergency; /* set flag */
1719 if (g->gckind == KGC_INC) 1669 if (g->gckind == KGC_GEN)
1720 fullinc(L, g);
1721 else
1722 fullgen(L, g); 1670 fullgen(L, g);
1671 else
1672 fullinc(L, g);
1723 g->gcemergency = 0; 1673 g->gcemergency = 0;
1724} 1674}
1725 1675