Подтвердить что ты не робот

Как решить проблему фрагментации памяти

У нас иногда возникали проблемы, из-за которых наши длительные серверные процессы (работающие на Windows Server 2003) породили исключение из-за отказа в распределении памяти. Наше подозрение в том, что эти распределения не выполняются из-за фрагментации памяти.

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

1) Используйте Windows Куча с низкой фрагментацией

2) jemalloc - как используется в Firefox 3

3) Doug Lea malloc

Наш серверный процесс разработан с использованием кросс-платформенного кода на С++, поэтому любое решение будет идеально также кросс-платформенным (операционные системы do * nix страдают от такого рода фрагментации памяти?).

Кроме того, я прав, полагая, что LFH теперь является механизмом распределения памяти по умолчанию для Windows Server 2008/Vista?... Будут ли мои текущие проблемы "уходить", если наши клиенты просто обновят свой сервер os?

4b9b3361

Ответ 1

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

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

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

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

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

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

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

Кроме того, с хорошим распределителем кучи, таким как Doug Lea's, что делает размеры блоков более похожими, не нужно, потому что распределитель уже будет использовать схему двухэтапного bucketing, что сделает совершенно ненужным искусственную настройку переданных размеров к malloc() - фактически, его менеджер кучи делает это для вас автоматически гораздо более надежно, чем приложение сможет вносить коррективы.

Ответ 2

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

Предполагая, что ваше приложение ведет себя следующим образом:
Выделить 10MB
Выделить 1 байт
Бесплатно 10MB
(oops, мы не освободили 1 байт, но кто заботится о 1 крошечном байте)

Это кажется очень маленькой утечкой, , вы вряд ли заметите это при мониторинге всего выделенного объема памяти. Но эта утечка в конечном итоге заставит вашу память приложений выглядеть так:
.
.
Бесплатно - 10MB
.
.
[Выделено -1 байт]
.
.
Бесплатно - 10MB
.
.
[Выделено -1 байт]
.
.
Бесплатно - 10MB
.
.

Эта утечка не будет замечена... пока вы не захотите выделить 11 МБ
Предполагая, что ваши мини-карты содержат всю информацию о памяти, я рекомендую использовать DebugDiag для обнаружения возможных утечек. В отчете сгенерированной памяти внимательно изучите подсчет распределения (не размер).

Ответ 3

Как вы полагаете, Doug Lea malloc может работать хорошо. Это перекрестная платформа, и она была использована в судоходном коде. По крайней мере, его легко интегрировать в свой код для тестирования.

Работая в среде с фиксированной памятью в течение ряда лет, эта ситуация, безусловно, является проблемой даже в нефиксированных средах. Мы обнаружили, что распределители CRT имеют тенденцию сильно ухудшаться с точки зрения производительности (скорость, эффективность потерянного пространства и т.д.). Я твердо верю, что если у вас есть обширная потребность в хорошем распределении памяти в течение длительного периода времени, вы должны написать свой собственный (или посмотреть, будет ли что-то вроде dlmalloc работать). Трюк получает что-то написанное, которое работает с вашими шаблонами распределения, и это имеет больше общего с эффективностью управления памятью, как и почти все.

Дайте dlmalloc попробовать. Я определенно даю ему большие пальцы. Он также достаточно настраивается, поэтому вы можете повысить эффективность, изменив некоторые параметры времени компиляции.

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

Ответ 4

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

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

Вы можете использовать _CrtDumpMemoryLeaks(); чтобы сбросить утечки памяти в окно отладки при запуске сборки отладки, однако я считаю, что это специфично для компилятора Visual C. (это в crtdbg.h)

Ответ 5

Я подозреваю утечку, прежде чем подозревать фрагментацию.

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

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

Ответ 6

@nsaners - Я уверен, что проблема сводится к фрагментации памяти. Мы проанализировали minidumps, которые указывают на проблему, когда выделяется большой (5-10 мб) фрагмент памяти. Мы также отслеживали процесс (на месте и в разработке) для проверки утечек памяти - ни один из них не был обнаружен (объем памяти, как правило, довольно низкий).

Ответ 7

Проблема возникает в Unix, хотя обычно это не так плохо.

Куча с низким уровнем рецессии помогла нам, но мои коллеги клянутся Smart Heap (в течение нескольких лет он использовался в нескольких наших продуктах). К сожалению, из-за других обстоятельств мы не смогли использовать Smart Heap на этот раз.

Мы также рассматриваем выделение блоков/фрагментов и пытаемся использовать подходы/стратегии, долгосрочные вещи здесь, весь запрос там, краткосрочные вещи там и т.д.

Ответ 8

Как обычно, вы обычно можете потерять память, чтобы получить некоторую скорость.

Этот метод не полезен для распределителя общего назначения, но он имеет место.

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

Ответ 9

если вы говорите о Win32 - вы можете попытаться что-то сжать, используя LARGEADDRESSAWARE. У вас будет ~ 1 ГБ дополнительной дефрагментированной памяти, поэтому ваше приложение будет фрагментировать ее дольше.