Эффективно выделяет множество короткоживущих мелких объектов - PullRequest
10 голосов
/ 28 января 2010

У меня есть небольшой класс (16 байт в 32-битной системе), который мне нужно динамически распределять. В большинстве случаев время жизни любого данного экземпляра очень короткое. Некоторые экземпляры также могут передаваться через границы потоков.

Проведя некоторое профилирование, я обнаружил, что моя программа, похоже, тратит больше времени на выделение и освобождение вещей, чем на самом деле тратит их, поэтому я хочу заменить новый по умолчанию и удалить что-то, что немного более эффективно.

Для большого объекта (соединения БД, как это бывает, которые дорого построить, а не распределить), я уже использую систему пула, однако это включает в себя список для хранения «свободных» объектов, а также мьютекс для безопасности потока. Между мьютексом и списком он на самом деле работает хуже, чем с базовым new / delete для маленьких объектов.

Я нашел несколько небольших распределителей объектов в Google, однако они, похоже, используют глобальный / статический пул, который не используется потокобезопасным способом, что делает их непригодными для моего использования: (

Какие еще варианты у меня есть для эффективного управления памятью таких маленьких объектов?

Ответы [ 3 ]

1 голос
/ 28 января 2010

Может быть, попытаться использовать Google tcmalloc ? Он оптимизирован для быстрого выделения / освобождения в многопоточной программе и имеет небольшие издержки для небольших объектов.

1 голос
/ 29 января 2010

Некоторые экземпляры также могут передаваться через границы потоков

Только "некоторые"? Так что, возможно, вы можете позволить себе доплатить за это, если это делает те, которые не передаются другим потокам, дешевле. Существуют различные способы получения одного распределителя на поток и исключения необходимости блокировки при выделении или освобождении в потоке, которому принадлежит распределитель. Я не знаю, что может быть возможно в вашей программе:

  • Скопируйте объекты через границу потока, а не передавая их.

  • Сделайте так, чтобы, если по какой-либо причине они были переданы другому потоку, они возвращались в исходный поток для освобождения. Это не обязательно должно происходить очень часто, вы можете поставить несколько в очередь в получающем потоке и позже передать их обратно в сообщении. Это, конечно, предполагает, что поток, которому принадлежит распределитель, собирается остаться.

  • Имеет два свободных списка для каждого распределителя, один синхронизированный (к которому объекты добавляются, когда они освобождаются из другого потока), и один несинхронизированный. Только если несинхронизированный список пуст и вы размещаете (и, следовательно, в потоке, которому принадлежит распределитель), вам нужно заблокировать синхронизированный свободный список и переместить все его текущее содержимое в несинхронизированный список. Если объекты, передаваемые в другие потоки, встречаются редко, это, в основном, устраняет конфликты на мьютексе и значительно сокращает количество раз, которое оно берется вообще.

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

Делая шаг назад, часто ли ваше приложение попадает в состояние, в котором вы знаете, что все ячейки, выделенные после определенного момента (возможно, немного в прошлом), больше не используются? Если это так, и если предположить, что деструктор ваших маленьких объектов не делает ничего ужасно срочного, то не беспокойтесь об освобождении ячеек вообще - в «определенной точке» создайте новый распределитель и пометьте старый как больше не используемый для новые распределения. Когда вы «достигнете состояния», освободите весь распределитель и его основной буфер. Если «определенная точка» и «состояние» одновременны, все проще - просто сбросьте свой распределитель.

0 голосов
/ 28 января 2010

Вы можете убедиться, что используете кучу низкой фрагментации . Он включен по умолчанию в Vista и более поздних версиях, но я не думаю, что это так с более ранними ОС. Это может существенно повлиять на скорость выделения небольших объектов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...