Как обойти фрагментацию кучи в программе на сервере C++?

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

Давайте предположим, что я приложил все усилия, чтобы минимизировать фрагментацию кучи во время выполнения в моем приложении сервера VC++, но все же оно накапливается и вызывает проблемы. Я мог бы, например, автоматически перезапускать приложение каждый месяц или каждые полмиллиона обработанных запросов - безопасно остановить его и безопасно запустить снова с новой кучей. Что еще я могу сделать, чтобы обойти фрагментацию кучи?

4 ответа

Хорошей отправной точкой является включение кучи с низкой фрагментацией и проверка того, фрагментируется ли она.

  HANDLE heaps[1025];
  DWORD nheaps = GetProcessHeaps((sizeof(heaps) / sizeof(HANDLE)) - 1, heaps);
  for (DWORD i = 0; i < nheaps; ++i) {
    ULONG  enableLFH = 2;
    HeapSetInformation(heaps[i], HeapCompatibilityInformation, &enableLFH, sizeof(enableLFH));
  }

Этот недавно представленный диспетчер памяти включен по умолчанию в Vista/Server 2008 ... Так что, если вы решите, что мир лучше на более новой серверной ОС, это может быть причиной.

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

Существует инструмент vmmap, который дает обзор памяти и дает хороший обзор, если происходит фрагментация.

Тот же ответ, что и здесь: Как обнаружить и оценить фрагментацию кучи в моей программе на C++?

напишите свой собственный менеджер памяти, адаптированный к вашим шаблонам распределения памяти. Или купить один (например, смарт-куча).

Поскольку фрагментация зависит от ваших шаблонов распределения памяти / шаблонов освобождения, лучший ответ трудно дать. Но вы могли бы взглянуть на распределители фиксированного размера или взглянуть на страницу умной кучи, как они обрабатывают распределение. Есть также много статей на эту тему. Попробуйте, например, http://www.memorymanagement.org/articles/

Или вы можете взглянуть на FastMM4 - с открытым исходным кодом, но в Pascal/Delphi

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

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

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

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

Другие вопросы по тегам