Как решить Фрагментацию памяти - PullRequest
45 голосов
/ 14 сентября 2008

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

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

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

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

3) Даг Леа Маллок

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

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

Ответы [ 10 ]

34 голосов
/ 14 сентября 2008

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

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

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

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

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

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

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

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

15 голосов
/ 12 октября 2008

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

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

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

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

5 голосов
/ 14 сентября 2008

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

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

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

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

2 голосов
/ 14 сентября 2008

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

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

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

1 голос
/ 14 сентября 2008

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

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

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

1 голос
/ 14 сентября 2008

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

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

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

1 голос
/ 14 сентября 2008

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

1 голос
/ 14 сентября 2008

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

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

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

0 голосов
/ 03 ноября 2018

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

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

Это был старый трюк UNIX с демонами, когда потоков еще не было.

0 голосов
/ 29 ноября 2016

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

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