Почему аллокация памяти в языках со сборкой мусора быстрее, чем в языках без них?

1,00
р.
Уже не первый раз слышу, что скорость аллокации в куче в C# или Java быстрее, чем в C++. Я не могу понять, почему это может быть: аллокация в куче подразумевает поиск свободной страницы в памяти. Как это можно ускорить и правдивы ли слухи?

Ответ
Да, эти слухи правдивы и имеют под собой основания.
Дело в том, что в языках наподобие C++ аллокация обычно подразумевает поиск свободного блока в списке свободных блоков. При этом, если программа многопоточная, может понадобиться ещё и глобальная блокировка. После нахождения свободного блока необходимо ещё и скорректировать список свободных блоков, и разместить в выделенном блоке дополнительную информацию.
В языках наподобие C# аллокация намного проще. Для нового элемента память выделяется просто на верху heap-памяти, и таким образом, аллокация сводится к простому
Interlocked.Increment(heapPtr, requestedSize)
что, конечно, намного быстрее поиска по списку свободных блоков.
В чём же разница? Дело в том, что сборщик мусора в .NET выполняет кроме самой сборки ещё и уплотнение кучи (heap compaction): дыры в куче, возникающие на месте собранного мусора, заполняются другими объектами, и все указатели на них сдвигаются. Пример:
Аллоцированные объекты:
[ объект №1 ] [ объект №2 ] [ о. №3 ] [ о. №4 ] [ о. №5 ] ^ | heapptr
Первая фаза сборки мусора (собраны объекты №1 и №4):
[ объект №2 ] [ о. №3 ] [ о. №5 ] ^ | heapptr
Уплотнение:
[ объект №2 ] [ о. №3 ] [ о. №5 ] ^ | heapptr
В результате, рантайм может аллоцировать новые объекты всегда на верху кучи, не боясь того, что дыры в куче займут слишком много места.
В C++ нет надёжного способа определить, где находятся указатели на данный объект, поэтому трюк с уплотнением кучи невозможен.

Однако же, C++ (в отдельных случаях) вполне может ускорить аллокации за счёт кастомных аллокаторов, которые могут затребовать сразу большой кусок памяти у рантайма, и раздавать его объектам.

На самом деле сборка мусора сложнее, чем я описал. Вот тут, например, есть начальные сведения о том, как происходит сборка мусора в .NET.