lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]

On 2017-03-29 22:51, John Dunn wrote:
> If I have a userdata that wraps a limited system resource ( ie file 
> handle, socket, large block of C memory, etc ), is there a way to 
> make the userdata more likely to be garbage collected?

I don't think there is built-in machinery for this.  In particular,

> It seems like a way to tag something to always be garbage collected 
> as soon as there are no longer any references might work.

is essentially impossible, as you'd need to scan everything to be sure
that there are no references left, which amounts to a full collection
cycle and doesn't gain you anything.  I also cannot think of a way to
build some refcounting contraption on top with no manual cues as that
would run into the same problem.

So you cannot collect only userdata.

But clever use of `collectgarbage( "step", size )` might be good enough.
Two strategies to try:

1) Naive approach:

Every time you allocate a limited resource, do a large-ish step
(potentially based on collectgarbage "count" for percentages - but then
also take a look at the pause and step multiplier).  It's not a full
collection cycle (so it's faster), but gives a good chance that things
will be collected in a timely manner.

(For the special case "large block of C memory" this is the correct
approach:  Step size is the size of that block in kilobytes.)

2) Counting:

In the constructor increment a count, and decrement in the
destructor/__gc.  Also in the constructor, check how many you have and
do some collection based on that.  (So if you have few then don't
collect at all, whereas if you're at the hard limit you'd do a full
collection(*) and hope to get some slots back.  In between, do steps of
varying size.)  Keep in mind that __gc metamethods run at the very end
of a collection phase, so expect to see bursts of releases with long
gaps in between.

(*) Or several - if a thing with __gc holds a reference to something
that holds a reference to your limited resource (nest arbitrarily
deeply), this may take longer to resolve.  While Lua will happily
traverse them all in one collection cycle, some of the __gc methods
might accidentally (or intentionally) resurrect one of the nodes in the
chain, and then it will take another full cycle to progress further.
(But don't loop until at least one was freed - if all are live that's an
endless loop.)

-- nobody