Вопрос

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

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

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

Это было полезно?

Решение

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

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

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

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

Другие советы

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

Я предполагаю, что это 32-разрядная Windows XP.

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

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

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

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

Удачи вам!

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top