Было бы замечательно, если бы вы воссоздали проблему, с которой вы столкнулись с MVCE , и показали это: вы знаете, часто проблема, о которой вы думаете, является вашей проблемой ... это не проблема.
Как я могу точно определить причину вышеуказанных проблем с памятью (какие-либо инструменты / метрики?)
Учитывая приведенную здесь информацию, я бы предложил использовать профилировщик - gprof (компилировать с -g -pg), являющийся базовым c. Если у вас есть компилятор Intel, вы можете использовать vtune.
Существует бесплатная версия vtune , но я лично использовал только коммерческую версию.
Кроме того, вы можете вставить тайминги в свой код: из текстового описания , не ясно, сопоставимо ли время заполнения карты со временем, необходимым для ее удаления, или оно постоянно увеличивается при параллельном запуске. Я бы начал с того, если. Обратите внимание, что текущая версия mallo c () значительно оптимизирована для параллелизма (это Linux? - добавьте тег к вопросу, пожалуйста).
Конечно, когда вы стираете карту, миллионы free()
звонят по номеру std::~string()
- но вы должны быть уверены, что это проблема или нет: вы можете использовать лучший подход (многие упомянутый в ответах / комментариях) или пользовательский распределитель, поддерживаемый огромным блоком памяти, который вы создаете / уничтожаете как единое целое.
Если вы предоставите MVCE в качестве отправной точки, я или другие смогут prov ie последовательный ответ (это еще не ответ - но слишком длинный, чтобы быть комментарием)
Просто чтобы прояснить, программа намеренно никогда не распределяет вещи и одновременно освобождает других и имеет только 2 потока, один из которых предназначен только для удаления.
Имейте в виду, что для каждой строки на карте требуется один (или больше) new
и один delete
(на основе malloc()
и free()
соответственно), являющиеся строками либо в ключах, либо в значениях.
Что у вас есть в «значениях» карты?
Поскольку у вас есть map<string,<set<int>>
, у вас есть много выделений: каждый раз, когда вы выполняете map[string].insert(val)
нового ключа, Ваш код неявно вызывает malloc()
как для строки, так и для набора. Даже если ключ уже находится на карте, для нового int в наборе требуется выделить новый узел в наборе.
Таким образом, при построении структуры у вас действительно много выделений: ваша память очень фрагментирована. с одной стороны, и ваш код выглядит действительно «интенсивно малло c», что в принципе может привести к тому, что вызовы памяти будут голодать.
многопоточные выделения памяти / освобождения памяти
Одна особенность современной памяти Подсистемы, это то, что они оптимизированы для многоядерных систем: когда один поток выделяет память на одно ядро, это не глобальная блокировка, а локальная или локальная для ядра блокировка для локального пула потоков.
Это означает, что когда одному потоку нужно освободить память, выделенную другому, включается нелокальная (более медленная) блокировка.
Это означает, что наилучшим подходом является то, что каждый поток выделяет / освобождает собственную память Сказав, что в принципе вы можете оптимизировать много вашего кода с помощью структур данных, которые требуют меньшего количества malloc / free взаимодействий, ваш код будет более локальным по отношению к распределению памяти, если вы позволите каждому потоку:
- получить один блок данных
- построить
map<string,<set<int>>
- освободить его
И у вас есть два потока, которые неоднократно выполняют эту задачу .
ПРИМЕЧАНИЕ. Для обработки параллельных вычислителей требуется оперативная память, но уже сейчас вы используете два из них, одновременно загруженных по схеме двойной буферизации (одно заполнение, одно очищение). Вы уверены, что ваша система не перезагружается из-за нехватки ОЗУ?
Кроме того, этот подход является масштабируемым: вы можете использовать столько потоков, сколько захотите. В вашем подходе вы были ограничены двумя потоками - один строил структуру, а другой разрушал ее.
Оптимизация
Без MVCE трудно давать указания. Только идеи, которые вы только знаете, можно ли применить в настоящее время:
- заменить набор отсортированным вектором, зарезервированным во время создания
- заменить ключи карты плоским вектором с равным интервалом , отсортированные строки
- хранят ключи строк последовательно в плоском векторе, добавляют хэши, чтобы отслеживать ключи карты. Добавьте карту ha sh, чтобы отслеживать порядок строк в векторе.