Last active
September 18, 2025 15:19
-
-
Save eprosync/09098e0ff894fb2da0605aeac46a171a to your computer and use it in GitHub Desktop.
Just a casual write up on what to possibly do with current GC magic.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Proposal for an Updated GC, for the current 2.1.0-beta3 stable under gmngc. | |
| Generational Tri-Color GC, a non-copy GC with a rememberance and deferral set. uhhh... I might be wrong in a bit about the "non-copy" part. | |
| # Added Struct Format | |
| GCState->tiers[TIERS] - List of collectable objects graded per tier. | |
| GCState->currentwhite[TIERS] - Current white color per tier. | |
| GCState->deferral[TIERS-1] - Deferral linked list, objects marked already black are to be scanned in the higher tier cycle. | |
| GCState->remembered[TIERS-1] - Used as a reference link between two different tier objects. (TBD) | |
| GCheader->tier - Current tier this object is in | |
| GCheader->tiernext - Next object in the tier linked list | |
| # Tri-Color Basics & Example (from a current non-generational GC standpoint) | |
| Objects are marked as white, gray, black (two alternating whites per cycle indicating dead/alive). | |
| Propagation: traverse reachables objects from whites → gray → black. | |
| Sweep: reclaim whites, flip between the two white sets. | |
| Finalizer: calls for any objects that require a destruction call. | |
| (Write)Barriers: indicates to the marking system of a reference change, this makes them gray again for checking. | |
| This remains the same from the current system, only adjustments is the addition of a tier system, remember set and deferral set. | |
| Ex: {[1] = {}}, TAB1 = outer table, TAB2 = inner table, TAB3 = unreadable (not referenced anywhere) | |
| GC.Start => mark roots (like current env [_G], registry, etc are pushed into gray templist, marked all gray), swap currentwhite to WHITE1 | |
| GC.Propagate => traverse from roots to all reachable objects until exausted traversal. | |
| ex: TAB1 - WHITE0, TAB2 - WHITE0, TAB3 - WHITE0 | |
| Propagating from first in gray (_G), mark black and traverse -> TAB1 discovered from _G traversal -> TAB1 is now gray, push into gray | |
| Propagating from first in gray (TAB1), mark black and traverse -> TAB2 discovered from TAB1 traversal -> TAB2 is now gray, push into gray | |
| Propagating from first in gray (TAB2), mark black and traverse -> nothing else discovered. | |
| Results: TAB1 is now BLACK (found), TAB2 is now BLACK (found), TAB3 is still WHITE0 | |
| GC.Sweep => iterate all GC objects in existance and determine if black or old-white. | |
| ex: TAB1 - BLACK, TAB2 - BLACK, TAB3 - WHITE0 | |
| TAB1 is black so its alive an reachable, turn to WHITE1 (alive & ready for next full cycle) | |
| TAB2 is black so its alive an reachable, turn to WHITE1 (alive & ready for next full cycle) | |
| TAB3 is white0, indicating it wasn't traversed or discovered at all, ERASE. | |
| GC.Finalizer => special step for finalizer calls, like __gc (its what mmudata is for.) | |
| # Generational Structure | |
| The heap is divided into tiers (we call these generations). | |
| Each tier has its own object list, the union of all tiers = the global gc.root (just not the same order). | |
| Objects can be promoted to higher tiers to indicate increasing resistance to collection. (you can use debug.promote manually as well) | |
| Each tier can be collected at different rates, tier 0 (young) is collected most often. | |
| # Deferral Set | |
| While collecting a lower tier (like tier 0), you may encounter references to higher tiers. | |
| Instead of traversing them immediately, mark them and push them onto the deferral list. | |
| Later, when collecting tier 1, the deferral list is used as an additional root set. | |
| This defers work to the correct tier list. | |
| # Remembered Set | |
| When an old object gains a reference to a young object, the write barrier records that old object in the remembered set. | |
| During a tier 0 collection, the remembered set is treated as part of the root set. | |
| This guarantees that young objects reachable from old objects are marked. | |
| # Automated Tier Assignments | |
| Since some objects inside the GC can remain constantly active, for example: protos and constants, | |
| we can auto-promote them to the highest tier, since the possibility of them getting changed is very unlikely. | |
| As for things like traces, those will stay tier 0, as its expected to only be used temporarily. | |
| # Tri-Color Generational Example | |
| Like my previous example but insteatd we show what happens in the tier system, remember set and deferral set. | |
| Using bellow as the basis for this. | |
| TAB1 = TIER 0, TAB2 = TIER 1, TAB3 = TIER 0, TAB4 = TIER 1 (unreachable) | |
| ``` | |
| TAB1[1] = TAB2 | |
| TAB2[1] = TAB3 -- WRITE BARRIER, remember set triggered, remembered set linkes TAB3 to TAB2 | |
| ``` | |
| (GC.Start uses the gc_tier_select() to find what tier to start from, but lets say its from TIER 0 and then next cycle TIER 1) | |
| [TIER 0] | |
| GC.Start => mark roots (like current env [_G], registry, etc are pushed into gray templist, marked all gray), swap currentwhite to WHITE1 | |
| GC.Propagate => traverse from roots to all reachable objects until exausted traversal. | |
| Propagating from first in gray list (_G), mark BLACK and traverse -> TAB1 discovered from _G traversal -> TAB1 is now GRAY, push into gray | |
| Propagating from first in gray list (TAB1), mark BLACK and traverse -> TAB2 discovered but is from TIER 1 -> TAB2 is now BLACK, push into deferral[0] | |
| Propagating nothing in gray list -> nothing else discovered. | |
| Results: TAB1 -> BLACK, TAB2 -> GRAY + deferred, TAB3 -> WHITE0, not discovered, TAB4 -> not discovered. | |
| GC.Sweep => iterate all GC objects in TIER 0 linked list and determine if BLACK or OLD-WHITE (WHITE0). | |
| TAB1 is BLACK so its alive an reachable, turn to WHITE1 (alive & ready for next full cycle) | |
| TAB3 is WHITE0 so its probably not alive, check remembered set... | |
| => TAB3 is referenced to a TIER 1 object, skip sweep on this. | |
| Results: No objects destroyed. | |
| GC.Finalizer => for any mmudata that needs to a special destruction call. | |
| [TIER 1] | |
| GC.Start => mark roots from deferral[0], which contains TAB2 (BLACK) | |
| GC.Propagate => traverse from roots to all reachable objects until exausted traversal. | |
| Propagating from first in gray list (TAB2), mark BLACK and traverse -> TAB3 discovered from TAB2 traversal -> TAB3 is now GRAY, push into gray | |
| Propagating from first in gray list (TAB3), mark BLACK and traverse -> nothing left to traverse. | |
| Results: TAB1 -> WHITE1, TAB2 -> BLACK, TAB3 -> BLACK, TAB4 -> not discovered. | |
| GC.Sweep => iterate all GC objects in TIER 1 linked list and determine if BLACK or OLD-WHITE (WHITE0). | |
| TAB2 is BLACK so its alive an reachable, turn to WHITE1 (alive & ready for next full cycle) | |
| TAB4 is WHITE0 so its probably not alive, check remembered set..., not found, ERASE. | |
| Results: TAB4 is destroyed. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment