boost fast_pool_allocator иногда запрашивает огромное выделение

У меня есть многопоточное приложение, которое использует fast_pool_allocator (версия 1.55) под quickfix (1.13.3). Приложение выделяет большое количество объектов в течение дня, увеличиваясь более или менее линейно, пока мы не выключим его, используя порядка 32 ГБ виртуальной памяти к концу дня. Большинство распределений составляет порядка 200 МБ, поскольку мы наблюдаем рост объема виртуальной памяти приложения. Но затем, в какой-то момент, как правило, позже в тот же день, boost решает выделить 6 ГБ, хотя поток транзакций через приложение существенно не меняется.

Глядя на код распределителя, первое, что делает boost после распределения, устанавливает новый блок на куски. Функция simple_segregated_storage<SizeType>::segregate по адресу simple_segregated_storage.hpp:280. Мы подключили к процессу отладчик и заметили, что когда происходит гигантское выделение памяти, выполнение этой функции (что неудивительно) занимает много времени, особенно цикла for в строке 302. Это занимает целых 20-30 секунд, а этот код защищен мьютексом, поэтому каждый второй поток пытается что-то сделать в блоках распределителя. Это возмущает наших клиентов.

Вопросы:

  1. Почему он внезапно выделил 6 ГБ, если до этого он постоянно запрашивал блоки ~ 200 МБ весь день?
  2. Можно ли как-то ограничить выделение? Я бы предпочел, чтобы он чаще просил мелкие кусочки.
  3. Это неправильный распределитель? Я предполагаю, что это вопрос к разработчикам быстрых исправлений, но, похоже, это их предпочтительный путь. Объекты, которые используют распределитель, в основном std::map и std::multimap.

person John S    schedule 23.01.2015    source источник
comment
Итак, после 10 минут чтения документации я нахожу параметр MaxSize, который, по-видимому, является ограничением на количество фрагментов, выделяемых базовым пулом за один раз, и по умолчанию он равен 0 (вероятно, без ограничений). Вы изучили последствия просмотра MaxSize ненулевым значением?   -  person Yakk - Adam Nevraumont    schedule 24.01.2015
comment
Да, это было так. Я опубликую ответ. Спасибо.   -  person John S    schedule 26.01.2015


Ответы (1)


Как предложил Yakk выше, оказывается, что пул повышения позволяет вам указать MaxSize в шаблоне. Это немного странно, поскольку он работает в единицах «фрагментов», концепции, внутренней для реализации пула. ИМХО байты были бы естественнее, ну да ладно.

fast_pool_allocator определяется со значениями по умолчанию для всех аргументов шаблона (кроме первого). Я скопировал эти значения по умолчанию и изменил последнее. Для этого приложения размер фрагмента составляет 88 байт, но я предполагаю, что это зависит от класса на карте.

typedef std::map <int, std::vector <FieldMap*>, std::less<int>, 
                  boost::fast_pool_allocator<std::pair<const int, std::vector<FieldMap*>>,
                                             boost::default_user_allocator_new_delete,
                                             boost::details::pool::default_mutex,
                                             32,       // NextSize (default from boost)
                                             1500000   // MaxSize, in 88 byte chunks.
                                            >> Groups;

В этом случае 1 500 000 * 88 = 132 МБ, что примерно соответствует размеру выделенного пространства на данный момент.

person John S    schedule 26.01.2015
comment
MaxSize не для ограничения, это просто связано с количеством чанков, запрошенных у системы в следующий раз. См. этот сообщение - person jfly; 29.01.2017