Here is the model I use to describe what happens with the __gc metamethod.
An object (in the case of Lua, just full userdata) can be in one of two
states. Call them live and not-quite-dead-yet.
Objects make the transition from live to not-quite-dead-yet when the garbage
collector detects that there are no strong links left to them.
When this transition happens (or actually some time afterward in the case of
incremental GC), the __gc metamethod will be called. This metamethod can do
anything it likes including creating new strong links to the object but it
can't change the object back to live from not-quite-dead-yet. As a result
the __gc metamethod will only be called once for an object during its
This could presumably work just as well for tables, so presumably the
reasons for its exclusion for tables have to do with:
1. The most common cases for use of __gc metamethods are in cleaning up
foreign resources which would be managed by userdata; and
2. Adding __gc metamethod support for tables makes tables more expensive to
collect and Lua creates a lot of tables; and
3. __gc metamethod support places restrictions on the design of the garbage
collector and limiting its use limits those restrictions; and
4. Understanding what the __gc metamethod does is a bit tricky and hence it
should be viewed as an expert tool to some extent. Its use with userdata, on
the other hand, is fairly straightforward.