The first thing you learn about garbage collection is that is fiendishly difficult to derive any useful analyses. Every system ends up being so workload-dependent that it becomes practically impossible to round out any design guidelines ("it's the cache, stupid" is still pretty much as far as the field has got). Every system has a worst case, and these worst cases have a nasty tendency to actually occur in real systems.
Richard Jones' book is an excellent introduction, although perhaps a little dated now. For example, there is little discussion of latency issues in threaded systems, which is where the "stop the world" approach has its major failing. Whilst the problem shares some characteristics with the distributed GC, discussed in a chapter by Lins in the book, it is also a distinct scenario.
Unfortunately the general awareness of GC issues is drastically poor. People associate garbage collection with poor performance and focus on just one aspect of its runtime performance, brushing over the fact that the issues are nowhere near that clear-cut (Linus is certainly correct that cache misses due to lazy allocation can be a problem; however it is not the single defining characteristic of garbage collection's runtime behaviour - there are a lot more factors, both negative and positive, on how a runtime GC system behaves).
Worse, this sort of attitude is still prevalent, which misses the point so badly I don't know where to start refuting it. This sounds like the same reasoning that led somebody to ask how to write a KDE application in assembly to me. jwz says it rather succinctly I think : " Most of the time, throwing memory and CPU at the problem is still cheaper than throwing programmer time at the problem, even when you multiply the CPUs/memory by the number of users". It bears thinking about.
Addendum: I wish Advogato wouldn't replace diary entries in recent log. Its notion of when a day begins and ends does not tally with mine ...