2008-09-29 6 views
11

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

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

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

+0

Я думаю, вы, вероятно, хотите избежать фрагментации, а не дефрагментации? – 2008-09-29 21:26:27

+0

Моя ставка на C++ - но это правда: на вопрос нельзя ответить, если базовая «парадигма» неизвестна .... – Georgi 2008-09-29 21:27:59

+0

Спасибо, Дуглас, я исправил это! – 2008-09-29 21:28:07

ответ

14

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

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

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

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

2

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

1

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

См. Некоторые общие идеи по этому вопросу here.

1

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

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

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

1

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

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

5

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

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

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

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

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

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

Удачи!

4

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

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

2

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

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

Однако, поскольку вам необходимо хранить данные изображения, вы также можете обойти это с помощью File Mapping as a memory store - это можно сделать так, чтобы у вас была память, доступная и доступная, но не используя виртуальные адреса вообще.

0

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

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