Hmmm, the garbage collector is a black box and has its own complicated heuristics for managing memory usage, but you are describing a mechanism that depends rather heavily on certain assumed behaviours. At the least, that gives the garbage collector less flexibility to change its own behaviour, lest it invalidate the assumptions made by the external allocator.
This is a situation where something is better than nothing. The heuristics we used with Hugs were pretty lame -I don't think they even worked as I'd intended- but they were good enough to get the job done. In fact, the application ran brilliantly: small GC pauses, little wasted memory. So, no, I don't see a heavy dependence or an extreme sensitivity to GC behaviour.
(In the image processing example, images were megabytes and an expression like (x + (y * mask)) would generate 2 intermediate images (several megabytes) while doing just 2 reductions in Haskell.)
I think I'd be tempted to try to use a more predictable allocation scheme given the size of the objects involved. Perhaps arenas?
Aren't arenas a form of explicit memory management? Explicit memory management was inappropriate for this example because the objects were manipulated by non-IO operations: programmers couldn't track the lifetime of an object because it depended on the order that thunks were evaluated. Note that this is _exactly_ what MallocPtrs/ ForeignObjs/ ForeignPtrs were invented to deal with. (Indeed, the first ever application was a (different) image processing library.)
But there seems to be no way to reasonably decide how often one should call these. Doesn't it depend on the garbage collector's own parameters too?
It probably does. It might even vary from one kind of application to another. But I don't think it is very sensitive to those parameters. The goal here is to behave tolerably (e.g., not do a full GC on a 100Mb heap 20 times per second) not optimally. [other topics answered separately] -- Alastair