Defer freeing of mega block groups to avoid quadratic worst case GC performance
Fixes #19897 (closed) in the following way:
- The megablock free list remains sorted and coalesced, but during GCs, we will use a secondary free list that is neither sorted nor coalesced.
- At the end of a GC run, we can then sort the secondary free list once (
O(n log n)
) and perform a single merge pass to merge it into the actual free list (O(n)
)
That way, we are asymptotically faster compared to the situation explained in the above issue, where every individual free call incurs a linear search on the free list, resulting in O(n^2)
runtime in the worst case.
You can see the difference in runtime of the final measured GC of the reproducer from the original issue in the following graph:
The overall runtime of the reproducer also slightly improved:
If more documentation in the code is required, please let me know!
I also added a comment about another potential case of "accidentally quadratic" that I didn't tackle in this PR, because it didn't occur (yet) in practice.