Win32 HeapCreate () initialSize не поддерживает большие выделения

У нас проблема с использованием HeapCreate () / HeapAlloc () для больших выделений (> 512 КБ)

Мы разрабатываем серверное приложение C ++, выполняющее некоторые операции «обработки изображений» одновременно над несколькими изображениями. Должно работать долго без перезагрузки.

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

Это означает, что мы используем всю необходимую память в начале, и общий объем памяти не должен расти (если все в порядке).
Наша боль — это фрагментация. Размер входящих изображений может варьироваться от 400К до, возможно, 50М, и обработка каждого из них приводит к соответствующим (пропорциональным размеру изображения) относительно большим выделениям OPENCV. Сценарии обработки (и связанные с ними выделения) различаются, в зависимости от особенностей изображения, действия по выделению / освобождению выполняются очень интенсивно, и через некоторое время мы получаем фрагментацию. Некоторые локальные оптимизации были разработаны с учетом незначительных улучшений.
На самом деле, после прибл. Мы имеем эффекты, связанные с нехваткой памяти / фрагментацией. 50000-70000 изображений, что не очень приемлемо. Текущее решение — перезапуск сервера, что далеко от идеала.

Первоначально наивное предложение по решению проблемы было:

  • У нас есть своя собственная куча, изначально выделяющая всю необходимую память.
  • Все необходимые «большие» выделения OPENCV (и ТОЛЬКО те), перенаправленные в эту кучу
  • В данный момент приходит фрагментация, мы прекращаем ввод и завершаем все запущенные задания.
  • Это означает, что все связанные с изображением выделения освобождаются.
  • Проверьте кучу и очистите ее при необходимости (например, из-за утечек памяти)
  • Теперь мы имеем абсолютно пустую кучу и можем начинать с нуля. Снова откройте ввод.

Простой проектный концептуальный проект быстро выяснил следующее:

  • HeapCreate (), первоначально выделяющий 250M, увеличивается на 10M каждый раз, когда я вызываю из него HeapAlloc ()! Странно, не правда ли?
  • Как было установлено с помощью HeapWalk (), выделенная память была зарезервирована не в одном непрерывном блоке, а в виде списка из более чем 500 фрагментов по 512 КБ каждый. Так что ни один из них не подходит для моего запроса 10M и кучи, вызванной для обработки незафиксированной памяти

Кажется, Win32 Custom Heap оптимизирована только для небольших выделений, и я не смог найти способ использовать его для своих нужд 🙁
VirtualAlloc (), кажется, решение, но это очень низкоуровневый API, и его использование означает разработку моей собственной системы управления памятью, кажется, своего рода переосмысление колеса.

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

-1

Решение

Несколько идей:

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

  2. Непонятно, действительно ли HeapAlloc для больших выделений выделяется из зарезервированной памяти кучи. MSDN является несколько расплывчатым и иногда противоречивым, но страница на куча с низкой фрагментацией (LFH) говорит, что выделения больше 16 КБ не используют LFH. Это может означать, что куча отслеживает его для вас, но на самом деле удовлетворяет большим выделениям из вызовов VirtualAlloc, а не из зарезервированной памяти. Если это так, использование кучи может только ухудшить ситуацию. (В любом случае, возможно, стоит попробовать с включенным LFH и без него.)

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

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

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]