стандартная производительность распределителя std :: map по сравнению с распределителем блоков - PullRequest
9 голосов
/ 08 марта 2012

Я читал в кулинарной книге по оптимизации C ++, что стандартный распределитель для контейнеров STL, таких как std :: list, std :: set, std :: multi_set, std :: map, e std :: multi_map, можно заменить наболее производительный распределитель блоков .

Распределитель блоков имеет более высокую производительность, низкую фрагментацию и эффективное кэширование данных.

Я обнаружил в сети FSBAllocator, который утверждает, чтоБыть быстрее, чем стандарт.http://warp.povusers.org/FSBAllocator/

Я пробовал это с помощью std :: map и обнаружил, что, кажется, действительно быстрее, но мой вопрос заключается в том, как реализация STL может быть настолько медленнее, чем конкретный распределитель, и каковы недостаткидругого распределителя, чем стандарт, с точки зрения переносимости и надежности?Мой код должен компилироваться на различных архитектурах (win32, osx, linux).Кто-нибудь имел опыт работы с подобным распределителем блоков фиксированного размера?

1 Ответ

13 голосов
/ 08 марта 2012

Распределитель блоков выполняет одно большое выделение для свободного хранилища / кучи, а затем внутренне разделяет эту память на куски. Один недостаток здесь заключается в том, что он распределяет этот кусок (который должен быть большим, и часто определяемым пользователем для каждого случая использования), так что даже если вы не используете все это, эта память связана. Во-вторых, стандартный распределитель памяти построен поверх new / delete, который, в свою очередь, часто строится поверх malloc / free. Хотя я и не помню, гарантированно ли при всех обстоятельствах malloc / free будет поточно-ориентированным, но так оно и есть.

Но, наконец, причина того, почему распределители блоков работают так хорошо, заключается в том, что у них есть информация, которой нет у стандартных распределителей, и им не нужно покрывать очень широкий набор вариантов использования. Например, если вы сделали std::map< int, int >(), и он выделил 1 МБ, вы, вероятно, разозлились бы, но если бы вы сделали std::map< int, int, std::less< int >, block_alloc< 1024 * 1024 > >(), вы бы ожидали этого. Стандартные распределители не выделяются в блоках, они запрашивают новую память через новую, а новые, в свою очередь, вообще не имеют контекста. Он получает запрос памяти произвольного размера и должен найти непрерывное число байтов для возврата. Что делает большинство реализаций, так это то, что они имеют набор областей памяти, которые они поддерживают в различных кратных единицах (например, более или менее вероятно, что область для 4 байтов, вероятно, будет присутствовать, так как запросы на 4 байта очень распространены). Если запрос не является даже кратным, становится труднее вернуть хороший кусок, не теряя места и вызывая фрагментацию. В основном, управление памятью произвольных размеров очень трудно сделать, если вы хотите, чтобы оно было близко к постоянному времени, низкой фрагментации, поточно-ориентированному и т. Д.

Документация Boost pool содержит полезную информацию о том, как может работать хороший распределитель блоков.

...