diff options
Diffstat (limited to 'lgc.c')
-rw-r--r-- | lgc.c | 84 |
1 files changed, 51 insertions, 33 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lgc.c,v 2.8 2004/08/10 19:17:23 roberto Exp roberto $ | 2 | ** $Id: lgc.c,v 2.9 2004/08/24 20:12:06 roberto Exp roberto $ |
3 | ** Garbage Collector | 3 | ** Garbage Collector |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -23,13 +23,11 @@ | |||
23 | #include "ltm.h" | 23 | #include "ltm.h" |
24 | 24 | ||
25 | 25 | ||
26 | #define GCSTEPSIZE (40*sizeof(TValue)) | 26 | #define GCSTEPSIZE 1000 |
27 | #define STEPMUL 2 | 27 | #define STEPMUL 2 |
28 | #define GCSWEEPMAX 40 | 28 | #define GCSWEEPMAX 10 |
29 | #define GCSWEEPCOST 1 | 29 | #define GCSWEEPCOST 30 |
30 | #define GCFINALIZECOST (10*sizeof(TValue)) | 30 | #define GCFINALIZECOST 100 |
31 | #define WAITNEXTCYCLE (40 * GCSTEPSIZE) | ||
32 | #define WAITNEXTCYCLEGN (200 * GCSTEPSIZE) | ||
33 | 31 | ||
34 | 32 | ||
35 | #define FIXEDMASK bitmask(FIXEDBIT) | 33 | #define FIXEDMASK bitmask(FIXEDBIT) |
@@ -408,10 +406,11 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_int32 count) { | |||
408 | global_State *g = G(L); | 406 | global_State *g = G(L); |
409 | int whitebit = otherwhite(g); | 407 | int whitebit = otherwhite(g); |
410 | int deadmask = whitebit | FIXEDMASK; | 408 | int deadmask = whitebit | FIXEDMASK; |
411 | while ((curr = *p) != NULL) { | 409 | int generational = g->gcgenerational; |
410 | while ((curr = *p) != NULL && count-- > 0) { | ||
412 | if ((curr->gch.marked ^ whitebit) & deadmask) { | 411 | if ((curr->gch.marked ^ whitebit) & deadmask) { |
413 | lua_assert(!isdead(g, curr) || testbit(curr->gch.marked, FIXEDBIT)); | 412 | lua_assert(!isdead(g, curr) || testbit(curr->gch.marked, FIXEDBIT)); |
414 | if (!G(L)->gcgenerational || isdead(g, curr)) | 413 | if (!generational || isdead(g, curr)) |
415 | makewhite(g, curr); | 414 | makewhite(g, curr); |
416 | if (curr->gch.tt == LUA_TTHREAD) | 415 | if (curr->gch.tt == LUA_TTHREAD) |
417 | sweepwholelist(L, &gco2th(curr)->openupval); | 416 | sweepwholelist(L, &gco2th(curr)->openupval); |
@@ -424,17 +423,11 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_int32 count) { | |||
424 | g->rootgc = curr->gch.next; /* adjust first */ | 423 | g->rootgc = curr->gch.next; /* adjust first */ |
425 | freeobj(L, curr); | 424 | freeobj(L, curr); |
426 | } | 425 | } |
427 | if (count-- == 0) break; | ||
428 | } | 426 | } |
429 | return p; | 427 | return p; |
430 | } | 428 | } |
431 | 429 | ||
432 | 430 | ||
433 | static void sweepstrings (lua_State *L) { | ||
434 | global_State *g = G(L); | ||
435 | sweepwholelist(L, &G(L)->strt.hash[g->sweepstrgc++]); | ||
436 | } | ||
437 | |||
438 | 431 | ||
439 | static void freelist (lua_State *L, GCObject **p) { | 432 | static void freelist (lua_State *L, GCObject **p) { |
440 | while (*p) { | 433 | while (*p) { |
@@ -532,6 +525,7 @@ static void remarkupvals (global_State *g) { | |||
532 | 525 | ||
533 | static void atomic (lua_State *L) { | 526 | static void atomic (lua_State *L) { |
534 | global_State *g = G(L); | 527 | global_State *g = G(L); |
528 | int aux; | ||
535 | lua_assert(g->gray == NULL); | 529 | lua_assert(g->gray == NULL); |
536 | /* remark occasional upvalues of (maybe) dead threads */ | 530 | /* remark occasional upvalues of (maybe) dead threads */ |
537 | remarkupvals(g); | 531 | remarkupvals(g); |
@@ -554,7 +548,11 @@ static void atomic (lua_State *L) { | |||
554 | g->sweepstrgc = 0; | 548 | g->sweepstrgc = 0; |
555 | g->sweepgc = &g->rootgc; | 549 | g->sweepgc = &g->rootgc; |
556 | g->gcstate = GCSsweepstring; | 550 | g->gcstate = GCSsweepstring; |
557 | if (g->gcgenerational++ > 20) g->gcgenerational = 0; | 551 | aux = g->gcgenerational; |
552 | g->gcgenerational = (g->estimate <= 4*g->prevestimate/2); | ||
553 | if (!aux) /* last collection was full? */ | ||
554 | g->prevestimate = g->estimate; /* keep estimate of last full collection */ | ||
555 | g->estimate = g->totalbytes; /* first estimate */ | ||
558 | } | 556 | } |
559 | 557 | ||
560 | 558 | ||
@@ -562,6 +560,14 @@ static l_mem singlestep (lua_State *L) { | |||
562 | global_State *g = G(L); | 560 | global_State *g = G(L); |
563 | /*lua_checkmemory(L);*/ | 561 | /*lua_checkmemory(L);*/ |
564 | switch (g->gcstate) { | 562 | switch (g->gcstate) { |
563 | case GCSpause: { | ||
564 | /* start a new collection */ | ||
565 | if (g->gcgenerational) | ||
566 | atomic(L); | ||
567 | else | ||
568 | markroot(L); | ||
569 | return 0; | ||
570 | } | ||
565 | case GCSpropagate: { | 571 | case GCSpropagate: { |
566 | if (g->gray) | 572 | if (g->gray) |
567 | return propagatemark(g); | 573 | return propagatemark(g); |
@@ -571,33 +577,31 @@ static l_mem singlestep (lua_State *L) { | |||
571 | } | 577 | } |
572 | } | 578 | } |
573 | case GCSsweepstring: { | 579 | case GCSsweepstring: { |
574 | sweepstrings(L); | 580 | lu_mem old = g->totalbytes; |
581 | sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]); | ||
575 | if (g->sweepstrgc >= g->strt.size) /* nothing more to sweep? */ | 582 | if (g->sweepstrgc >= g->strt.size) /* nothing more to sweep? */ |
576 | g->gcstate = GCSsweep; /* end sweep-string phase */ | 583 | g->gcstate = GCSsweep; /* end sweep-string phase */ |
584 | g->estimate -= old - g->totalbytes; | ||
577 | return GCSWEEPCOST; | 585 | return GCSWEEPCOST; |
578 | } | 586 | } |
579 | case GCSsweep: { | 587 | case GCSsweep: { |
588 | lu_mem old = g->totalbytes; | ||
580 | g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); | 589 | g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); |
581 | if (*g->sweepgc == NULL) { /* nothing more to sweep? */ | 590 | if (*g->sweepgc == NULL) { /* nothing more to sweep? */ |
582 | checkSizes(L); | 591 | checkSizes(L); |
583 | g->gcstate = GCSfinalize; /* end sweep phase */ | 592 | g->gcstate = GCSfinalize; /* end sweep phase */ |
584 | } | 593 | } |
585 | return GCSWEEPCOST; | 594 | g->estimate -= old - g->totalbytes; |
595 | return GCSWEEPMAX*GCSWEEPCOST; | ||
586 | } | 596 | } |
587 | case GCSfinalize: { | 597 | case GCSfinalize: { |
588 | if (g->tmudata) { | 598 | if (g->tmudata) { |
589 | GCTM(L); | 599 | GCTM(L); |
590 | return GCFINALIZECOST; | 600 | return GCFINALIZECOST; |
591 | } | 601 | } |
592 | else { /* no more `udata' to finalize */ | 602 | else { |
593 | if (g->gcgenerational) { | 603 | g->gcstate = GCSpause; /* end collection */ |
594 | atomic(L); | 604 | return 0; |
595 | return WAITNEXTCYCLEGN; | ||
596 | } | ||
597 | else { | ||
598 | markroot(L); /* may restart collection */ | ||
599 | return WAITNEXTCYCLE; | ||
600 | } | ||
601 | } | 605 | } |
602 | } | 606 | } |
603 | default: lua_assert(0); return 0; | 607 | default: lua_assert(0); return 0; |
@@ -607,18 +611,30 @@ static l_mem singlestep (lua_State *L) { | |||
607 | 611 | ||
608 | void luaC_step (lua_State *L) { | 612 | void luaC_step (lua_State *L) { |
609 | global_State *g = G(L); | 613 | global_State *g = G(L); |
610 | l_mem lim = (g->nblocks - (g->GCthreshold - GCSTEPSIZE)) * STEPMUL; | 614 | l_mem lim = (g->totalbytes - (g->GCthreshold - GCSTEPSIZE)) * STEPMUL; |
615 | /*printf("step(%c): ", g->gcgenerational?'g':' ');*/ | ||
611 | do { | 616 | do { |
617 | /*printf("%c", "_pswf"[g->gcstate]);*/ | ||
612 | lim -= singlestep(L); | 618 | lim -= singlestep(L); |
619 | if (g->gcstate == GCSpause) | ||
620 | break; | ||
613 | } while (lim > 0); | 621 | } while (lim > 0); |
614 | g->GCthreshold = g->nblocks + GCSTEPSIZE - lim/STEPMUL; | 622 | /*printf("\n");*/ |
615 | lua_assert((long)g->nblocks + (long)GCSTEPSIZE >= lim/STEPMUL); | 623 | if (g->gcstate != GCSpause) |
624 | g->GCthreshold = g->totalbytes + GCSTEPSIZE; /* - lim/STEPMUL; */ | ||
625 | else { | ||
626 | /*printf("---\n");*/ | ||
627 | lua_assert(g->totalbytes >= g->estimate); | ||
628 | g->GCthreshold = 2*g->estimate; | ||
629 | if (g->GCthreshold < g->totalbytes + GCSTEPSIZE) | ||
630 | g->GCthreshold = g->totalbytes + GCSTEPSIZE; | ||
631 | } | ||
616 | } | 632 | } |
617 | 633 | ||
618 | 634 | ||
619 | void luaC_fullgc (lua_State *L) { | 635 | void luaC_fullgc (lua_State *L) { |
620 | global_State *g = G(L); | 636 | global_State *g = G(L); |
621 | if (g->gcstate == GCSpropagate || g->gcgenerational) { | 637 | if (g->gcstate <= GCSpropagate || g->gcgenerational) { |
622 | g->gcgenerational = 0; | 638 | g->gcgenerational = 0; |
623 | /* reset sweep marks to sweep all elements (returning them to white) */ | 639 | /* reset sweep marks to sweep all elements (returning them to white) */ |
624 | g->sweepstrgc = 0; | 640 | g->sweepstrgc = 0; |
@@ -631,6 +647,7 @@ void luaC_fullgc (lua_State *L) { | |||
631 | } | 647 | } |
632 | /* finish any pending sweep phase */ | 648 | /* finish any pending sweep phase */ |
633 | while (g->gcstate != GCSfinalize) { | 649 | while (g->gcstate != GCSfinalize) { |
650 | lua_assert(g->gcstate == GCSsweepstring || g->gcstate == GCSsweep); | ||
634 | singlestep(L); | 651 | singlestep(L); |
635 | } | 652 | } |
636 | markroot(L); | 653 | markroot(L); |
@@ -639,7 +656,8 @@ void luaC_fullgc (lua_State *L) { | |||
639 | singlestep(L); | 656 | singlestep(L); |
640 | g->gcgenerational = 0; /* keep it in this mode */ | 657 | g->gcgenerational = 0; /* keep it in this mode */ |
641 | } | 658 | } |
642 | g->GCthreshold = g->nblocks + GCSTEPSIZE; | 659 | lua_assert(g->estimate == g->totalbytes); |
660 | g->GCthreshold = 2*g->estimate; | ||
643 | luaC_callGCTM(L); /* call finalizers */ | 661 | luaC_callGCTM(L); /* call finalizers */ |
644 | } | 662 | } |
645 | 663 | ||
@@ -686,7 +704,7 @@ void luaC_linkupval (lua_State *L, UpVal *uv) { | |||
686 | } | 704 | } |
687 | else { /* sweep phase: sweep it (turning it into white) */ | 705 | else { /* sweep phase: sweep it (turning it into white) */ |
688 | makewhite(g, o); | 706 | makewhite(g, o); |
689 | lua_assert(g->gcstate != GCSfinalize); | 707 | lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); |
690 | } | 708 | } |
691 | } | 709 | } |
692 | } | 710 | } |