Then you have to manage their lifetimes 'manually'. Iterate, ultimately you remove GC altogether.
If GC is the future (and it seems it is) of language runtime, then some kind of control will be needed for situations like this. Different pools, explicit tagging of 'long-lived' or 'cache value' or some such during allocation?
I think that's reductio ad absurdum. It's typical in long-running applications to have a class of memory unlike the rest, that will live the entire lifetime of the application. I see no problem with being able to tell the GC "this memory will always be used," or just allocating it outside of the GC entirely, while still wanting all of the benefits of GC elsewhere in the application.
"Different pools, explicit tagging of 'long-lived' or 'cache value' or some such during allocation?"
The idea that immediately came to my mind is that given that the site is probably load-balanced, the best thing to do would be to take the site out of the load balancer while the big GC runs, then put it back in. I wonder if there's some way to hook that GC event. So, "pools", but at a higher level.
We register for notifications from the GC using a magic threshold number that could mean anything.
Then we quickly notify the rest of the webs a GC is pending on our "message bus". They let us know they are safe from GC at the moment. If they are not you are in a pickle.
Then we notify HAProxy that we are about to run a GC and ask it to tell us when it is done draining the current requests and taking our web offline.
Once notified we perform the GC manually
Then we notify HAProxy that we are done with the GC so it can add us back to the pool.
Or you could just tell haproxy you're going to be low priority for a little bit and not worry about every single last request never being processed on GCing server.
I think you've got it exactly backwards. By the time you've dealt with some of the various complexities manual memory management, for example:
- handling memory with a dynamic lifetime
(with cycle detection as an important corner case)
- improving allocation performance
- preventing heap fragmentation
- thread-local allocators (for multi-threaded scalability)
...
I think you're approaching a garbage collector. In fact, I'd even go so far as to say there is a memory-management analog for Greenspun's tenth rule:
Any sufficiently complicated, long-lived program that manually manages memory contains an ad hoc, informally-specified, bug-ridden, slow implementation of a garbage collector.
I agree there's a place for some amount of "hinting" to the garbage collector about the lifetime of some special objects, but, to me, the important thing is that you only need it for the extreme cases.
It's possible and practical. The MPS allows you to have manually-managed pools alongside GC'ed pools in the same heap: http://www.ravenbrook.com/project/mps/
Useful for long-lived data that doesn't change frequently.
If GC is the future (and it seems it is) of language runtime, then some kind of control will be needed for situations like this. Different pools, explicit tagging of 'long-lived' or 'cache value' or some such during allocation?