Not to mention ... stop-the-world garbage collectors have a good reason for doing what they do. They are defragmenting the memory. You get that for free, when in C++ you would have to deal with hell if your app is doing lots of allocations ... see the shit the Firefox devs had to go through to alleviate the problems of heap fragmentation, and its still a problem.
In 32-bit land, it's welcome to OutOfMemoryException because managed code can't allocate a big enough chunk when returning to C#.
No free lunch :)
Either recycle processes often or reserve big enough contiguous chunks in managed code before calling out to the bad C++ code, no amount of good citizenship in managed code will stop the poorly written native code from fragmenting the hell out of your address space.
Side rant: it's part of the reason that my Palm Pre will sometimes just hang for a second at the worst times, such as when I go to answer the phone. :(
For a good overview, read "Uniprocessor Garbage Collection Techniques" by Paul Wilson (check google scholar). Richard Jones's _Garbage Collection: Algorithms for Automatic Dynamic Memory Management_ is more in depth.
The problem tends to be that you need to tune it, and even as you have tuned it, you can not promise that under special condition it will fall back to a more primitive collector since the optimality it was tuned for doesn't hold anymore.
I would never argue giving up garbage collection entirely because of these failure scenarios. I would much rather look at moving some critical part of the code out to a language with manual allocation, and let it perform the latency-sensitive bits.
Another mid-ground is to have separate isolate processes (heaps really) that can be stop-the-world collected without blocking each other. Erlang makes great use of this to accomplish "soft realtime", among other things.