"This gets even more painful when considering the multitude of heaps in your average browser, chrome layers written in Web technologies, and (iirc) Firefox using a non-moving, non-generational GC. Whereas a multi-process browser has a vastly cleaner solution to all of that: it simply disposes of an entire address space (including all fragments and leaks) when it's done with a rendering context."
You're overstating the impact of JS here. JS memory is allocated in large "chunks" in Firefox. This minimizes external fragmentation. When a rendering context is destroyed, all of the chunks are immediately destroyed with it; because of compartments, we know that there are no chrome JS objects interspersed with the content JS objects, so we can just destroy these large chunks. So the amount of JS-related fragmentation resulting from closing rendering contexts is minimal in practice.
Regarding chrome layers written in Web technologies, this is somewhat orthogonal, since in all browsers chrome allocations stick around for the lifetime of the browser. C++ code has no compaction story, and, unlike JS, it has no reasonable path to achieve compaction in the future.