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

354
20 августа 2017, 03:10

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

Answer 1

Да, эти слухи правдивы и имеют под собой основания.

Дело в том, что в языках наподобие 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.

READ ALSO
Как запустить консольное приложение c# на сервере

Как запустить консольное приложение c# на сервере

охайо, написал телеграмм бота который выборочно автопостит из группы вк в канал(вебхуки и обработка сообщений не нужна)Бот написан шарповским...

374
combobox, запретить ввод данных кроме тех что загружены и подсвечивать по мере ввода

combobox, запретить ввод данных кроме тех что загружены и подсвечивать по мере ввода

Подскажите, элемент combobox в него загружен справочникМожно ли каким то образом по мере ввода показывать в выпадающем списке те данные которые...

216
Найти и удалить объект по его Uid/Name. WPF C#

Найти и удалить объект по его Uid/Name. WPF C#

Имеется Canvas, для него есть несколько дочерних объектов Image с прописанными Uid/NameВозможно ли из кода бихаинд найти заданные Image по Uid/Name и удалить...

303
Как воспроизводить файлы с помощью winmm.dll в C#?

Как воспроизводить файлы с помощью winmm.dll в C#?

Всем приветПытаюсь воспроизвести файл

236