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

Как избежать фрагментации кучи?

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

Приложение написано на С++ и работает под управлением Windows XP.

EDIT: Приложение выполняет некоторую предварительную обработку данных изображения, таких как переформатирование, вычисление таблиц поиска, извлечение дополнительных изображений, представляющих интерес... Приложению требуется около 2 ГБ оперативной памяти во время обработки, из которых около 1,5 ГБ могут использоваться для данных изображения.

4b9b3361

Ответ 1

Если вы занимаетесь медицинской обработкой изображений, вероятно, вы выделяете большие блоки за раз (512x512, 2 байта на пиксельные изображения). Фрагментация вас укусит, если вы выделите меньшие объекты между выделениями буферов изображений.

Написание пользовательского распределителя не обязательно сложно для конкретного случая использования. Вы можете использовать стандартный распределитель С++ для объекта Image, но для пиксельного буфера вы можете использовать пользовательское распределение, которое управляется в вашем объекте Image. Вот быстрый и грязный план:

  • Использовать статический массив структур, каждая структура имеет:
    • Твердый блок памяти, который может содержать N изображений - фрагментация поможет контролировать фрагментацию - попробуйте начальное N из 5 или около того
    • Параллельный массив bools, указывающий, используется ли соответствующее изображение
  • Чтобы выделить, найти массив для пустого буфера и установить его флаг
    • Если ни один не найден, добавьте новую структуру в конец массива
  • Чтобы освободить, найдите соответствующий буфер в массиве (-ах) и очистите логический флаг

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

Ответ 2

Есть ответы, но трудно быть общим, не зная подробностей проблемы.

Я предполагаю 32-разрядную Windows XP.

Попытайтесь избежать необходимости использования 100 МБ непрерывной памяти, если вам не повезло, несколько случайных DLL загрузятся в неудобные точки через ваше доступное адресное пространство, быстро сокращая очень большие области непрерывной памяти. В зависимости от того, какие API-интерфейсы вам нужны, это может быть довольно сложно предотвратить. Может быть довольно удивительно, как просто выделение нескольких блоков памяти размером 400 МБ в дополнение к некоторому "нормальному" использованию памяти может оставить вам нигде, чтобы выделить финальный "маленький" блок размером 40 МБ.

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

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

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

Удачи!

Ответ 3

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

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

Ответ 4

Без дополнительной информации о проблеме (например, язык), одна вещь, которую вы можете сделать, заключается в том, чтобы избежать оттока распределения путем повторного использования распределений и не выделять, работать и освобождать. Аллокатор, такой как dlmalloc, обрабатывает фрагментацию лучше, чем кучи Win32.

Ответ 5

То, что вы будете нажимать здесь, - это предел диапазона виртуальных адресов, который с 32b Windows дает вам не более 2 ГБ. Вы также должны знать, что использование графического API, такого как DirectX или OpenGL, будет использовать обширные части этих 2 ГБ для фреймового буфера, текстур и подобных данных.

1,5-2 GB для приложения 32b довольно сложно достичь. Самый элегантный способ сделать это - использовать 64-битное приложение OS и 64b. Даже с 64-битным OS и 32b-приложением это может быть несколько жизнеспособным, если вы используете LARGE_ADDRESS_AWARE.

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

Ответ 6

Угадайте здесь, что вы имели в виду избегать фрагментации, а не избегать дефрагментации. Также предполагаем, что вы работаете с неконтролируемым языком (возможно, с или С++). Я бы предположил, что вы выделяете большие куски памяти, а затем обслуживаете выделение кучи из выделенных блоков памяти. Этот пул памяти, поскольку содержит большие блоки памяти, менее подвержен фрагментации. Подводя итог, вы должны реализовать специализированный распределитель памяти.

См. некоторые общие идеи по этому здесь.

Ответ 7

Я полагаю, что вы используете что-то неуправляемое, потому что на управляемых платформах система (сборщик мусора) заботится о фрагментации.

Для C/С++ вы можете использовать другой распределитель, чем стандартный. (там были alrady некоторые потоки о распределителях на stackowerflow).

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

Ответ 8

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

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

Ответ 9

Если вы можете изолировать именно те места, где вы, вероятно, выделите большие блоки, вы можете (в Windows) напрямую вызвать VirtualAlloc вместо того, чтобы проходить через диспетчер памяти. Это позволит избежать фрагментации в обычном диспетчере памяти.

Это простое решение, и вам не требуется использовать пользовательский менеджер памяти.