Hi Chris.
I've run into a strangeness with my TLS-based web server. It seems that, for every incoming request, three file descriptors are used (they all seem to be sockets), and they aren't immediately cleaned up.
With keep-alive disabled, they CAN be disposed of, but it takes an explicit gc() call. With keep-alive active, they aren't garbage, so they stick around even with a gc() call. (Which is probably correct, but there might need to be a limit on how many get retained.)
[...]
What are the three FDs used for? Presumably one of them is the actual incoming socket, but the other two are less obvious.
This phenomenon does not seem to happen with non-SSL ports, possibly relating to the simpler shutdown sequence for unencrypted sockets.
This isn't usually a major problem, as the GC does get run eventually, but under certain types of workloads, it's easy to overload it and run out of FDs. This can be triggered by removing the gc() call from each request, and then any of these will spin up until the process FD limit is hit:
[...]
So I think it's probably not purely an issue with a client library misbehaving.
Is there a better way to handle this than simply forcing garbage collection every request?
The best way is to break the cycle before dropping the object on the floor (or to not introduce it to begin with) or destruct the problematic objects explicitly.
To identify the cycles you may want to log the cycles detected by the gc; take a look at base_server/roxen.pike:reinstall_gc_callbacks().
/grubba