Пользовательский пул распределитель в C ++ помимо boost :: pool

У меня есть сценарий использования в C ++, где функция, которую я вызываю много раз, создает несколько локальных небольших векторов с динамическим размером. После профилирования моей программы я заметил, что в std :: vector :: free () тратится слишком много времени. Казалось, что естественным (C ++ — esque) решением такой проблемы было переключение распределителя по умолчанию на что-то более подходящее для моего сценария использования. В частности, использование стратегии пула памяти показалось бы здесь разумным. Тем не менее, boost :: pool_alloc пока не доставляет никаких проблем. Я заставил его работать, но, хотя в моей маленькой, но часто вызываемой функции распределения выполняются быстрее (мы будем вызывать эту функцию f ()), она вызывает зависание функции, вызывающей f (), прежде чем вернуться к очень долгое время.

Еще более профилирование показывает, что все это время (буквально за десятки минут до того, как я устал от ожидания) тратится в pool_allocator :: orders_free (). Я воспроизвел это же поведение (хотя и не столь экстремально) в простой тестовой программе, и кажется, что действительно, когда большой набор построенных векторов возвращает свою память в пул одноэлементных данных, функция просто очень долго зависает перед возвратом ,

Если кто-нибудь знает способ избежать этого поведения или другой распределитель пула C ++, который не страдает от такой проблемы, я был бы очень признателен!

3

Решение

Я написал свою собственную пару раз, где распределение и освобождение происходит очень быстро, когда все начинается.
1. Создайте карту бассейнов по размеру.
2. Каждый пул имеет двусвязный список блоков.
3. Каждый блок имеет дополнительное пространство спереди и сзади для списка узлов и ссылки на пул владельцев, проверки размера и т. Д.
4. Распределение происходит быстро, потому что вам просто нужно найти первый пул с размером> = размер вашего блока и отменить выбор первой записи.
5. Распределение происходит быстро, потому что у вас есть указатель на пул прямо в блоке памяти, поэтому все, что вам нужно сделать, — это снова включить его.
6. Вы можете создать кучу пустых пулов при запуске. Затем при каждом выделении сначала попробуйте удалить список из пула. Если это не помогло, тогда используйте malloc (). Когда блок освобожден, добавьте его обратно в пул вместо того, чтобы освобождать его.
7. Как только ваше приложение будет работать стабильно, все ресурсы будут поступать прямо из связанного списка пулов, и освобождение будет происходить сразу же … Супер быстро.
8. Когда ваша программа выйдет, освободите () всю память в пулах.

0

Другие решения

Исходя из вашего вопроса, я предполагаю, что

  • Это только одна функция
  • Размер векторов ограничен (вы говорите, что он маленький)
  • Функция не вызывается рекурсивно слишком часто

Если это так, подумайте об использовании выделенной в стеке памяти вместо динамически выделяемой памяти. Вы можете сделать это, либо не используя вектор, но используя std::array<> и некоторый индикатор размера (если хранимый тип является тривиально конструируемым) или некоторый необработанный буфер памяти фиксированного размера и размещения нового, или обертка последнего в класс распределителя для использования вектора с этим классом распределителя.

Если ваша проблема с производительностью ограничена таким небольшим участком кода, я бы не стал использовать такие инструменты управления памятью общего назначения, как boost :: pool, но использовал бы что-то очень специализированное для данной ситуации.

0

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector