Управление памятью в приложениях с интенсивным использованием памяти - PullRequest
7 голосов
/ 23 января 2009

Если вы разрабатываете приложение с интенсивным использованием памяти на C ++ в Windows, вы предпочитаете написать свой собственный менеджер памяти для выделения памяти из виртуального адресного пространства или вы разрешаете CRT управлять вами и выполнять управление памятью за вас? Меня особенно беспокоит фрагментация, вызванная выделением и освобождением небольших объектов в куче. Поэтому я думаю, что процессу не хватит памяти, хотя памяти достаточно, но она фрагментирована.

Ответы [ 9 ]

38 голосов
/ 23 января 2009

Я думаю, что вам лучше всего не внедрять его, пока профили не докажут , что CRT фрагментирует память таким образом, что это ухудшает производительность вашего приложения. Ребята из CRT, ядра ОС и STL тратят много времени на размышления об управлении памятью.

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

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

Пока вы используете стандартные классы коллекций algorihtmns (такие как STL / BOOST), не составит труда подключить новый распределитель позже в цикле, чтобы исправить части вашей кодовой базы, которые делают должны быть исправлены. Маловероятно, что вам понадобится распределитель, закодированный вручную, для всей вашей программы.

4 голосов
/ 30 января 2010

Хотя большинство из вас указывают, что вам не следует писать собственный менеджер памяти, он все равно может быть полезен, если:

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

Если вы хотите написать собственный менеджер памяти, важно разделить его на следующие 4 части:

  1. часть, которая «перехватывает» вызовы malloc / free (C) и new / delete (C ++). Это довольно легко для new / delete (только глобальные операторы new и delete), но также для malloc / free это возможно («перезаписать» функции CRT, переопределить вызовы malloc / free, ...)
  2. часть, представляющая точку входа вашего менеджера памяти и вызываемая частью-перехватчиком
  3. часть, которая реализует фактический менеджер памяти. Возможно, у вас будет несколько реализаций этого (в зависимости от ситуации)
  4. часть, которая «украшает» выделенную память информацией о стеке вызовов, зонах перезаписи (или красных зонах), ...

Если эти 4 части четко разделены, также становится легко заменить одну часть на другую или добавить новую часть, например ::1010*

  • добавить реализацию менеджера памяти библиотеки Intel Tread Building Blocks (к части 3)
  • изменить часть 1 для поддержки новой версии компилятора, новой платформы или совершенно нового компилятора

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

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

Хотя вы можете делать аналогичные вещи с готовыми компонентами, они, как правило, имеют некоторые недостатки:

  • часто они серьезно тормозят работу приложения
  • часто они могут сообщать об утечках только в конце приложения, но не во время его работы

Но также постарайтесь быть реалистами: если у вас нет проблем с фрагментацией памяти, производительностью, утечками памяти или перезаписью памяти, нет реальной причины писать свой собственный менеджер памяти.

2 голосов
/ 23 января 2009

Исходя из моего опыта, фрагментация в основном является проблемой, когда вы постоянно выделяете и освобождаете большие буферы (например, более 16 КБ), поскольку именно они в конечном итоге вызовут нехватку памяти, если куча не может найдите достаточно большое место для одного из них.

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

В реализациях кучи по умолчанию не должно возникнуть проблем с поиском места для небольших буферов между предыдущими выделениями.

2 голосов
/ 23 января 2009

Это был SmartHeap от MicroQuill?

2 голосов
/ 23 января 2009

Раньше была отличная сторонняя библиотека для замены кучи для VC ++, но я больше не помню ее название. Наше приложение ускорилось на 30%, когда мы начали его использовать.

Редактировать: это SmartHeap - спасибо, ChrisW

1 голос
/ 23 января 2009

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

Я часто заканчиваю тем, что управляю такими объектами в std :: vector или чем-то похожем и явном, а не переопределяю процедуры выделения для класса. Во многих ситуациях куча действительно излишня, и шаблоны распределения настолько предсказуемы, что вам не нужно выделять в куче, а в какой-то гораздо более простой структуре, которая выделяет большие страницы из кучи, что требует меньших затрат на ведение бухгалтерского учета, чем выделение каждого отдельного экземпляра в куча.

Вот некоторые общие вещи для размышления:

Во-первых, небольшие объекты, которые быстро распределяются и уничтожаются, должны быть помещены в стек. Самое быстрое распределение - это те, которые никогда не делаются. Распределение стека также выполняется без какой-либо блокировки глобальной кучи, что хорошо для многопоточного кода. Выделение в куче в c / c ++ может быть относительно дорогим по сравнению с языками GC, такими как java, поэтому старайтесь избегать этого, если вам это не нужно.

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

1 голос
/ 23 января 2009

вы решили написать свой собственный менеджер памяти для выделения памяти из виртуального адресного пространства или вы разрешаете CRT взять на себя управление и управлять памятью для вас?

Стандартная библиотека часто достаточно хороша. Если это не так, вместо того, чтобы заменить его, меньшим шагом будет переопределение operator new и operator delete для определенных классов, а не для всех классов.

0 голосов
/ 26 января 2011

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

0 голосов
/ 23 января 2009

нет, я бы не стал.

Вероятность того, что я напишу лучший код, чем CRT, с теми, кто знает, сколько сотен человеко-лет вложено в него, невелика.

Я бы искал специализированную библиотеку вместо того, чтобы изобретать велосипед.

...