diff options
Diffstat (limited to '')
-rw-r--r-- | lgc.c | 67 | ||||
-rw-r--r-- | lgc.h | 12 | ||||
-rw-r--r-- | llimits.h | 8 | ||||
-rw-r--r-- | ltests.c | 8 | ||||
-rw-r--r-- | manual/manual.of | 28 | ||||
-rw-r--r-- | testes/gengc.lua | 11 |
6 files changed, 84 insertions, 50 deletions
@@ -93,6 +93,7 @@ | |||
93 | */ | 93 | */ |
94 | #define markobjectN(g,t) { if (t) markobject(g,t); } | 94 | #define markobjectN(g,t) { if (t) markobject(g,t); } |
95 | 95 | ||
96 | |||
96 | static void reallymarkobject (global_State *g, GCObject *o); | 97 | static void reallymarkobject (global_State *g, GCObject *o); |
97 | static l_obj atomic (lua_State *L); | 98 | static l_obj atomic (lua_State *L); |
98 | static void entersweep (lua_State *L); | 99 | static void entersweep (lua_State *L); |
@@ -831,10 +832,10 @@ static void freeobj (lua_State *L, GCObject *o) { | |||
831 | ** for next collection cycle. Return where to continue the traversal or | 832 | ** for next collection cycle. Return where to continue the traversal or |
832 | ** NULL if list is finished. | 833 | ** NULL if list is finished. |
833 | */ | 834 | */ |
834 | static GCObject **sweeplist (lua_State *L, GCObject **p, int countin) { | 835 | static GCObject **sweeplist (lua_State *L, GCObject **p, l_obj countin) { |
835 | global_State *g = G(L); | 836 | global_State *g = G(L); |
836 | int ow = otherwhite(g); | 837 | int ow = otherwhite(g); |
837 | int i; | 838 | l_obj i; |
838 | int white = luaC_white(g); /* current white */ | 839 | int white = luaC_white(g); /* current white */ |
839 | for (i = 0; *p != NULL && i < countin; i++) { | 840 | for (i = 0; *p != NULL && i < countin; i++) { |
840 | GCObject *curr = *p; | 841 | GCObject *curr = *p; |
@@ -1357,8 +1358,8 @@ static void setminordebt (global_State *g) { | |||
1357 | ** collection. | 1358 | ** collection. |
1358 | */ | 1359 | */ |
1359 | static void entergen (lua_State *L, global_State *g) { | 1360 | static void entergen (lua_State *L, global_State *g) { |
1360 | luaC_runtilstate(L, bitmask(GCSpause)); /* prepare to start a new cycle */ | 1361 | luaC_runtilstate(L, GCSpause, 1); /* prepare to start a new cycle */ |
1361 | luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */ | 1362 | luaC_runtilstate(L, GCSpropagate, 1); /* start new cycle */ |
1362 | atomic(L); /* propagates all and then do the atomic stuff */ | 1363 | atomic(L); /* propagates all and then do the atomic stuff */ |
1363 | atomic2gen(L, g); | 1364 | atomic2gen(L, g); |
1364 | setminordebt(g); /* set debt assuming next cycle will be minor */ | 1365 | setminordebt(g); /* set debt assuming next cycle will be minor */ |
@@ -1515,10 +1516,14 @@ static l_obj atomic (lua_State *L) { | |||
1515 | } | 1516 | } |
1516 | 1517 | ||
1517 | 1518 | ||
1519 | /* | ||
1520 | ** Do a sweep step. The normal case (not fast) sweeps at most GCSWEEPMAX | ||
1521 | ** elements. The fast case sweeps the whole list. | ||
1522 | */ | ||
1518 | static void sweepstep (lua_State *L, global_State *g, | 1523 | static void sweepstep (lua_State *L, global_State *g, |
1519 | int nextstate, GCObject **nextlist) { | 1524 | int nextstate, GCObject **nextlist, int fast) { |
1520 | if (g->sweepgc) | 1525 | if (g->sweepgc) |
1521 | g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); | 1526 | g->sweepgc = sweeplist(L, g->sweepgc, fast ? MAX_LOBJ : GCSWEEPMAX); |
1522 | else { /* enter next state */ | 1527 | else { /* enter next state */ |
1523 | g->gcstate = nextstate; | 1528 | g->gcstate = nextstate; |
1524 | g->sweepgc = nextlist; | 1529 | g->sweepgc = nextlist; |
@@ -1526,7 +1531,19 @@ static void sweepstep (lua_State *L, global_State *g, | |||
1526 | } | 1531 | } |
1527 | 1532 | ||
1528 | 1533 | ||
1529 | static l_obj singlestep (lua_State *L) { | 1534 | /* |
1535 | ** Performs one incremental "step" in an incremental garbage collection. | ||
1536 | ** For indivisible work, a step goes to the next state. When marking | ||
1537 | ** (propagating), a step traverses one object. When sweeping, a step | ||
1538 | ** sweeps GCSWEEPMAX objects, to avoid a big overhead for sweeping | ||
1539 | ** objects one by one. (Sweeping is inexpensive, no matter the | ||
1540 | ** object.) When 'fast' is true, 'singlestep' tries to finish a state | ||
1541 | ** "as fast as possible". In particular, it skips the propagation | ||
1542 | ** phase and leaves all objects to be traversed by the atomic phase: | ||
1543 | ** That avoids traversing twice some objects, such as theads and | ||
1544 | ** weak tables. | ||
1545 | */ | ||
1546 | static l_obj singlestep (lua_State *L, int fast) { | ||
1530 | global_State *g = G(L); | 1547 | global_State *g = G(L); |
1531 | l_obj work; | 1548 | l_obj work; |
1532 | lua_assert(!g->gcstopem); /* collector is not reentrant */ | 1549 | lua_assert(!g->gcstopem); /* collector is not reentrant */ |
@@ -1539,7 +1556,7 @@ static l_obj singlestep (lua_State *L) { | |||
1539 | break; | 1556 | break; |
1540 | } | 1557 | } |
1541 | case GCSpropagate: { | 1558 | case GCSpropagate: { |
1542 | if (g->gray == NULL) { /* no more gray objects? */ | 1559 | if (fast || g->gray == NULL) { |
1543 | g->gcstate = GCSenteratomic; /* finish propagate phase */ | 1560 | g->gcstate = GCSenteratomic; /* finish propagate phase */ |
1544 | work = 0; | 1561 | work = 0; |
1545 | } | 1562 | } |
@@ -1556,17 +1573,17 @@ static l_obj singlestep (lua_State *L) { | |||
1556 | break; | 1573 | break; |
1557 | } | 1574 | } |
1558 | case GCSswpallgc: { /* sweep "regular" objects */ | 1575 | case GCSswpallgc: { /* sweep "regular" objects */ |
1559 | sweepstep(L, g, GCSswpfinobj, &g->finobj); | 1576 | sweepstep(L, g, GCSswpfinobj, &g->finobj, fast); |
1560 | work = GCSWEEPMAX; | 1577 | work = GCSWEEPMAX; |
1561 | break; | 1578 | break; |
1562 | } | 1579 | } |
1563 | case GCSswpfinobj: { /* sweep objects with finalizers */ | 1580 | case GCSswpfinobj: { /* sweep objects with finalizers */ |
1564 | sweepstep(L, g, GCSswptobefnz, &g->tobefnz); | 1581 | sweepstep(L, g, GCSswptobefnz, &g->tobefnz, fast); |
1565 | work = GCSWEEPMAX; | 1582 | work = GCSWEEPMAX; |
1566 | break; | 1583 | break; |
1567 | } | 1584 | } |
1568 | case GCSswptobefnz: { /* sweep objects to be finalized */ | 1585 | case GCSswptobefnz: { /* sweep objects to be finalized */ |
1569 | sweepstep(L, g, GCSswpend, NULL); | 1586 | sweepstep(L, g, GCSswpend, NULL, fast); |
1570 | work = GCSWEEPMAX; | 1587 | work = GCSWEEPMAX; |
1571 | break; | 1588 | break; |
1572 | } | 1589 | } |
@@ -1596,14 +1613,15 @@ static l_obj singlestep (lua_State *L) { | |||
1596 | 1613 | ||
1597 | 1614 | ||
1598 | /* | 1615 | /* |
1599 | ** advances the garbage collector until it reaches a state allowed | 1616 | ** Advances the garbage collector until it reaches the given state. |
1600 | ** by 'statemask' | 1617 | ** (The option 'fast' is only for testing; in normal code, 'fast' |
1618 | ** here is always true.) | ||
1601 | */ | 1619 | */ |
1602 | void luaC_runtilstate (lua_State *L, int statesmask) { | 1620 | void luaC_runtilstate (lua_State *L, int state, int fast) { |
1603 | global_State *g = G(L); | 1621 | global_State *g = G(L); |
1604 | lua_assert(g->gckind == KGC_INC); | 1622 | lua_assert(g->gckind == KGC_INC); |
1605 | while (!testbit(statesmask, g->gcstate)) | 1623 | while (state != g->gcstate) |
1606 | singlestep(L); | 1624 | singlestep(L, fast); |
1607 | } | 1625 | } |
1608 | 1626 | ||
1609 | 1627 | ||
@@ -1618,8 +1636,13 @@ void luaC_runtilstate (lua_State *L, int statesmask) { | |||
1618 | static void incstep (lua_State *L, global_State *g) { | 1636 | static void incstep (lua_State *L, global_State *g) { |
1619 | l_obj stepsize = cast(l_obj, 1) << g->gcstepsize; | 1637 | l_obj stepsize = cast(l_obj, 1) << g->gcstepsize; |
1620 | l_obj work2do = applygcparam(g, gcstepmul, stepsize); | 1638 | l_obj work2do = applygcparam(g, gcstepmul, stepsize); |
1621 | do { /* repeat until pause or enough "credit" (negative debt) */ | 1639 | int fast = 0; |
1622 | l_obj work = singlestep(L); /* perform one single step */ | 1640 | if (work2do == 0) { /* special case: do a full collection */ |
1641 | work2do = MAX_LOBJ; /* do unlimited work */ | ||
1642 | fast = 1; | ||
1643 | } | ||
1644 | do { /* repeat until pause or enough work */ | ||
1645 | l_obj work = singlestep(L, fast); /* perform one single step */ | ||
1623 | if (g->gckind == KGC_GENMINOR) /* returned to minor collections? */ | 1646 | if (g->gckind == KGC_GENMINOR) /* returned to minor collections? */ |
1624 | return; /* nothing else to be done here */ | 1647 | return; /* nothing else to be done here */ |
1625 | work2do -= work; | 1648 | work2do -= work; |
@@ -1665,13 +1688,11 @@ static void fullinc (lua_State *L, global_State *g) { | |||
1665 | if (keepinvariant(g)) /* black objects? */ | 1688 | if (keepinvariant(g)) /* black objects? */ |
1666 | entersweep(L); /* sweep everything to turn them back to white */ | 1689 | entersweep(L); /* sweep everything to turn them back to white */ |
1667 | /* finish any pending sweep phase to start a new cycle */ | 1690 | /* finish any pending sweep phase to start a new cycle */ |
1668 | luaC_runtilstate(L, bitmask(GCSpause)); | 1691 | luaC_runtilstate(L, GCSpause, 1); |
1669 | luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */ | 1692 | luaC_runtilstate(L, GCScallfin, 1); /* run up to finalizers */ |
1670 | g->gcstate = GCSenteratomic; /* go straight to atomic phase ??? */ | ||
1671 | luaC_runtilstate(L, bitmask(GCScallfin)); /* run up to finalizers */ | ||
1672 | /* 'marked' must be correct after a full GC cycle */ | 1693 | /* 'marked' must be correct after a full GC cycle */ |
1673 | lua_assert(g->marked == gettotalobjs(g)); | 1694 | lua_assert(g->marked == gettotalobjs(g)); |
1674 | luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */ | 1695 | luaC_runtilstate(L, GCSpause, 1); /* finish collection */ |
1675 | setpause(g); | 1696 | setpause(g); |
1676 | } | 1697 | } |
1677 | 1698 | ||
@@ -182,12 +182,14 @@ | |||
182 | 182 | ||
183 | /* incremental */ | 183 | /* incremental */ |
184 | 184 | ||
185 | /* wait memory to double before starting new cycle */ | 185 | /* Number of objects must be LUAI_GCPAUSE% before starting new cycle */ |
186 | #define LUAI_GCPAUSE 200 | 186 | #define LUAI_GCPAUSE 300 |
187 | 187 | ||
188 | #define LUAI_GCMUL 300 /* step multiplier */ | 188 | /* Step multiplier. (Roughly, the collector handles LUAI_GCMUL% objects |
189 | for each new allocated object.) */ | ||
190 | #define LUAI_GCMUL 200 | ||
189 | 191 | ||
190 | /* how many objects to allocate before next GC step (log2) */ | 192 | /* How many objects to allocate before next GC step (log2) */ |
191 | #define LUAI_GCSTEPSIZE 8 /* 256 objects */ | 193 | #define LUAI_GCSTEPSIZE 8 /* 256 objects */ |
192 | 194 | ||
193 | 195 | ||
@@ -244,7 +246,7 @@ | |||
244 | LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o); | 246 | LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o); |
245 | LUAI_FUNC void luaC_freeallobjects (lua_State *L); | 247 | LUAI_FUNC void luaC_freeallobjects (lua_State *L); |
246 | LUAI_FUNC void luaC_step (lua_State *L); | 248 | LUAI_FUNC void luaC_step (lua_State *L); |
247 | LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask); | 249 | LUAI_FUNC void luaC_runtilstate (lua_State *L, int state, int fast); |
248 | LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency); | 250 | LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency); |
249 | LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz); | 251 | LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz); |
250 | LUAI_FUNC GCObject *luaC_newobjdt (lua_State *L, int tt, size_t sz, | 252 | LUAI_FUNC GCObject *luaC_newobjdt (lua_State *L, int tt, size_t sz, |
@@ -33,7 +33,8 @@ typedef unsigned long lu_mem; | |||
33 | typedef long l_obj; | 33 | typedef long l_obj; |
34 | #endif /* } */ | 34 | #endif /* } */ |
35 | 35 | ||
36 | #define MAX_LOBJ cast(l_obj, ~cast(lu_mem, 0) >> 1) | 36 | #define MAX_LOBJ \ |
37 | cast(l_obj, (cast(lu_mem, 1) << (sizeof(l_obj) * CHAR_BIT - 1)) - 1) | ||
37 | 38 | ||
38 | 39 | ||
39 | /* chars used as small naturals (so that 'char' is reserved for characters) */ | 40 | /* chars used as small naturals (so that 'char' is reserved for characters) */ |
@@ -44,7 +45,10 @@ typedef signed char ls_byte; | |||
44 | /* maximum value for size_t */ | 45 | /* maximum value for size_t */ |
45 | #define MAX_SIZET ((size_t)(~(size_t)0)) | 46 | #define MAX_SIZET ((size_t)(~(size_t)0)) |
46 | 47 | ||
47 | /* maximum size visible for Lua (must be representable in a lua_Integer) */ | 48 | /* |
49 | ** Maximum size for strings and userdata visible for Lua (should be | ||
50 | ** representable in a lua_Integer) | ||
51 | */ | ||
48 | #define MAX_SIZE (sizeof(size_t) < sizeof(lua_Integer) ? MAX_SIZET \ | 52 | #define MAX_SIZE (sizeof(size_t) < sizeof(lua_Integer) ? MAX_SIZET \ |
49 | : (size_t)(LUA_MAXINTEGER)) | 53 | : (size_t)(LUA_MAXINTEGER)) |
50 | 54 | ||
@@ -941,10 +941,10 @@ static int gc_printobj (lua_State *L) { | |||
941 | 941 | ||
942 | static int gc_state (lua_State *L) { | 942 | static int gc_state (lua_State *L) { |
943 | static const char *statenames[] = { | 943 | static const char *statenames[] = { |
944 | "propagate", "atomic", "enteratomic", "sweepallgc", "sweepfinobj", | 944 | "propagate", "atomic", "sweepallgc", "sweepfinobj", |
945 | "sweeptobefnz", "sweepend", "callfin", "pause", ""}; | 945 | "sweeptobefnz", "sweepend", "callfin", "pause", ""}; |
946 | static const int states[] = { | 946 | static const int states[] = { |
947 | GCSpropagate, GCSenteratomic, GCSatomic, GCSswpallgc, GCSswpfinobj, | 947 | GCSpropagate, GCSenteratomic, GCSswpallgc, GCSswpfinobj, |
948 | GCSswptobefnz, GCSswpend, GCScallfin, GCSpause, -1}; | 948 | GCSswptobefnz, GCSswpend, GCScallfin, GCSpause, -1}; |
949 | int option = states[luaL_checkoption(L, 1, "", statenames)]; | 949 | int option = states[luaL_checkoption(L, 1, "", statenames)]; |
950 | if (option == -1) { | 950 | if (option == -1) { |
@@ -957,9 +957,9 @@ static int gc_state (lua_State *L) { | |||
957 | luaL_error(L, "cannot change states in generational mode"); | 957 | luaL_error(L, "cannot change states in generational mode"); |
958 | lua_lock(L); | 958 | lua_lock(L); |
959 | if (option < g->gcstate) { /* must cross 'pause'? */ | 959 | if (option < g->gcstate) { /* must cross 'pause'? */ |
960 | luaC_runtilstate(L, bitmask(GCSpause)); /* run until pause */ | 960 | luaC_runtilstate(L, GCSpause, 1); /* run until pause */ |
961 | } | 961 | } |
962 | luaC_runtilstate(L, bitmask(option)); | 962 | luaC_runtilstate(L, option, 0); /* do not skip propagation state */ |
963 | lua_assert(G(L)->gcstate == option); | 963 | lua_assert(G(L)->gcstate == option); |
964 | lua_unlock(L); | 964 | lua_unlock(L); |
965 | return 0; | 965 | return 0; |
diff --git a/manual/manual.of b/manual/manual.of index ef1bdfd2..e6a3cd9e 100644 --- a/manual/manual.of +++ b/manual/manual.of | |||
@@ -664,7 +664,7 @@ Values equal to or less than 100 mean the collector will not wait to | |||
664 | start a new cycle. | 664 | start a new cycle. |
665 | A value of 200 means that the collector waits for | 665 | A value of 200 means that the collector waits for |
666 | the total number of objects to double before starting a new cycle. | 666 | the total number of objects to double before starting a new cycle. |
667 | The default value is 200; the maximum value is 1000. | 667 | The default value is 300; the maximum value is 1000. |
668 | 668 | ||
669 | The garbage-collector step multiplier | 669 | The garbage-collector step multiplier |
670 | controls the speed of the collector relative to | 670 | controls the speed of the collector relative to |
@@ -674,7 +674,9 @@ how many objects it marks or sweeps for each object created. | |||
674 | Larger values make the collector more aggressive. | 674 | Larger values make the collector more aggressive. |
675 | Beware that values too small can | 675 | Beware that values too small can |
676 | make the collector too slow to ever finish a cycle. | 676 | make the collector too slow to ever finish a cycle. |
677 | The default value is 300; the maximum value is 1000. | 677 | The default value is 200; the maximum value is 1000. |
678 | As a special case, a zero value means unlimited work, | ||
679 | effectively producing a non-incremental, stop-the-world collector. | ||
678 | 680 | ||
679 | The garbage-collector step size controls the | 681 | The garbage-collector step size controls the |
680 | size of each incremental step, | 682 | size of each incremental step, |
@@ -682,9 +684,7 @@ specifically how many objects the interpreter creates | |||
682 | before performing a step. | 684 | before performing a step. |
683 | This parameter is logarithmic: | 685 | This parameter is logarithmic: |
684 | A value of @M{n} means the interpreter will create @M{2@sp{n}} | 686 | A value of @M{n} means the interpreter will create @M{2@sp{n}} |
685 | objects between steps and perform equivalent work during the step. | 687 | objects between steps. |
686 | A large value (e.g., 60) makes the collector a stop-the-world | ||
687 | (non-incremental) collector. | ||
688 | The default value is 8, | 688 | The default value is 8, |
689 | which means steps of approximately @N{256 objects}. | 689 | which means steps of approximately @N{256 objects}. |
690 | 690 | ||
@@ -3306,43 +3306,43 @@ For options that need extra arguments, | |||
3306 | they are listed after the option. | 3306 | they are listed after the option. |
3307 | @description{ | 3307 | @description{ |
3308 | 3308 | ||
3309 | @item{@id{LUA_GCCOLLECT}| | 3309 | @item{@defid{LUA_GCCOLLECT}| |
3310 | Performs a full garbage-collection cycle. | 3310 | Performs a full garbage-collection cycle. |
3311 | } | 3311 | } |
3312 | 3312 | ||
3313 | @item{@id{LUA_GCSTOP}| | 3313 | @item{@defid{LUA_GCSTOP}| |
3314 | Stops the garbage collector. | 3314 | Stops the garbage collector. |
3315 | } | 3315 | } |
3316 | 3316 | ||
3317 | @item{@id{LUA_GCRESTART}| | 3317 | @item{@defid{LUA_GCRESTART}| |
3318 | Restarts the garbage collector. | 3318 | Restarts the garbage collector. |
3319 | } | 3319 | } |
3320 | 3320 | ||
3321 | @item{@id{LUA_GCCOUNT}| | 3321 | @item{@defid{LUA_GCCOUNT}| |
3322 | Returns the current amount of memory (in Kbytes) in use by Lua. | 3322 | Returns the current amount of memory (in Kbytes) in use by Lua. |
3323 | } | 3323 | } |
3324 | 3324 | ||
3325 | @item{@id{LUA_GCCOUNTB}| | 3325 | @item{@defid{LUA_GCCOUNTB}| |
3326 | Returns the remainder of dividing the current amount of bytes of | 3326 | Returns the remainder of dividing the current amount of bytes of |
3327 | memory in use by Lua by 1024. | 3327 | memory in use by Lua by 1024. |
3328 | } | 3328 | } |
3329 | 3329 | ||
3330 | @item{@id{LUA_GCSTEP}| | 3330 | @item{@defid{LUA_GCSTEP}| |
3331 | Performs a step of garbage collection. | 3331 | Performs a step of garbage collection. |
3332 | } | 3332 | } |
3333 | 3333 | ||
3334 | @item{@id{LUA_GCISRUNNING}| | 3334 | @item{@defid{LUA_GCISRUNNING}| |
3335 | Returns a boolean that tells whether the collector is running | 3335 | Returns a boolean that tells whether the collector is running |
3336 | (i.e., not stopped). | 3336 | (i.e., not stopped). |
3337 | } | 3337 | } |
3338 | 3338 | ||
3339 | @item{@id{LUA_GCINC} (int pause, int stepmul, int stepsize)| | 3339 | @item{@defid{LUA_GCINC} (int pause, int stepmul, int stepsize)| |
3340 | Changes the collector to incremental mode | 3340 | Changes the collector to incremental mode |
3341 | with the given parameters @see{incmode}. | 3341 | with the given parameters @see{incmode}. |
3342 | Returns the previous mode (@id{LUA_GCGEN} or @id{LUA_GCINC}). | 3342 | Returns the previous mode (@id{LUA_GCGEN} or @id{LUA_GCINC}). |
3343 | } | 3343 | } |
3344 | 3344 | ||
3345 | @item{@id{LUA_GCGEN} (int minormul, int minormajor, int majorminor)| | 3345 | @item{@defid{LUA_GCGEN} (int minormul, int minormajor, int majorminor)| |
3346 | Changes the collector to generational mode | 3346 | Changes the collector to generational mode |
3347 | with the given parameters @see{genmode}. | 3347 | with the given parameters @see{genmode}. |
3348 | Returns the previous mode (@id{LUA_GCGEN} or @id{LUA_GCINC}). | 3348 | Returns the previous mode (@id{LUA_GCGEN} or @id{LUA_GCINC}). |
diff --git a/testes/gengc.lua b/testes/gengc.lua index 3d4f67f8..d708d7fc 100644 --- a/testes/gengc.lua +++ b/testes/gengc.lua | |||
@@ -162,9 +162,16 @@ end | |||
162 | assert(collectgarbage'isrunning') | 162 | assert(collectgarbage'isrunning') |
163 | 163 | ||
164 | 164 | ||
165 | do print"testing stop-the-world collection" | ||
166 | collectgarbage("incremental", nil, 0) | ||
165 | 167 | ||
166 | -- just to make sure | 168 | -- each step does a complete cycle |
167 | assert(collectgarbage'isrunning') | 169 | assert(collectgarbage("step")) |
170 | assert(collectgarbage("step")) | ||
171 | |||
172 | -- back to default value | ||
173 | collectgarbage("incremental", nil, 200) | ||
174 | end | ||
168 | 175 | ||
169 | collectgarbage(oldmode) | 176 | collectgarbage(oldmode) |
170 | 177 | ||