OutOfMemoryException при создании большого растрового изображения в CF.NET - PullRequest
4 голосов
/ 18 ноября 2008

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

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

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

Есть ли способ предотвратить это исключение? Есть ли способ освободить нужную мне память (где бы она ни находилась) до того, как будет сгенерировано исключение?

Ответы [ 4 ]

1 голос
/ 18 ноября 2008

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

1 голос
/ 18 ноября 2008

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

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

Мне следует избегать выражений типа "нет решения".

Еще один важный момент: убедитесь, что вы вызываете Dispose () для каждого растрового изображения, когда закончите с ним.

0 голосов
/ 18 ноября 2008

Поскольку кажется, что вы столкнулись с ограничением устройства, которое ограничивает общий размер растрового пространства, которое вы можете создать (они, очевидно, создаются в видеопамяти, а не в общей памяти программы), одной из альтернатив является замена большого объекта растрового изображения используется здесь с простым старым блоком памяти Windows, обращаясь к нему для чтения и записи с помощью PInvoking функции BitBlt API.

Первоначально создать блок памяти довольно сложно, и вы, вероятно, захотите задать еще один SO вопрос по этому поводу (GCHandle.Alloc может использоваться здесь для создания «закрепленного» объекта, что означает, что .NET не разрешено перемещать это вокруг в памяти, что здесь критично). Я знаю, как это сделать, но я не уверен, что я делаю это правильно, и я предпочел бы получить мнение эксперта.

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

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

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

Обновление: на самом деле, идеальным подходом было бы иметь набор меньших блоков памяти, а не один большой (как я думал, была проблема с растровым подходом), но у вас уже достаточно сделать. Я работал с CF-приложениями, которые работают с объектами объемом 5 и 10 МБ, и в любом случае это не большая проблема (хотя это может быть большая проблема, когда этот фрагмент закреплен - я не знаю). Кстати, я всегда был удивлен OOMEs при создании BitMap, потому что я знал, что растровые изображения были намного меньше, чем доступная память, как и вы - теперь я знаю почему. Извините, я сначала подумал, что это легко решить.

0 голосов
/ 18 ноября 2008

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

Извините, но это, как правило, нецелесообразная техника рендеринга элементов управления (особенно в Compact Framework), для которой не существует исправления, если не считать увеличения физической памяти на КПК, что обычно невозможно (и часто не исправляет). проблема в любом случае, так как процесс CF ограничен 32 МБ независимо от того, сколько устройства доступно).

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

...