Silverlight: BitmapImage из потока выдает исключение (катастрофический сбой (исключение из HRESULT: 0x8000FFFF (E_UNEXPECTED)))

Мне нужно динамически загружать множество (иногда сотни) миниатюрных изображений. По соображениям производительности мне нужно делать это в ограниченном количестве запросов, я использую один запрос / ответ для тестирования. Я отправляю двоичные данные для изображений в ответе и загружаю их в BitmapImage с помощью MemoryStream. Это работает правильно, пока я не загружу более 80 эскизов, затем я получу исключение Catastrophic Failure. Чтобы убедиться, что мои данные не были повреждены, я несколько раз пытался загрузить BitmapImage с одним и тем же массивом байтов, и он вылетал после 80 или около того загрузок.

Вот пример того, как изображение загружается из байтового массива, байтовый массив, как известно, имеет допустимые данные изображения (png):

private BitmapImage LoadImage(byte[] imageData)
{
    BitmapImage img = new BitmapImage();
    MemoryStream stream = new MemoryStream(imageData);
    img.SetSource(stream); // Exception thrown here after too many images loaded.
    return img;
}

Затем я использую BitmapImage в качестве источника для элемента изображения на странице, но ошибка возникает в строке img.SetSource(...) выше.

Добавление GC.Collect() в цикл, в котором я загружаю миниатюрные изображения, позволяет мне загрузить еще несколько изображений, поэтому я думаю, что это как-то связано с управлением памятью, но я не знаю, что я могу сделать, чтобы исправить проблему.


person toby    schedule 08.07.2011    source источник
comment
Я не уверен, может ли это быть проблемой, но у MemoryStream есть свойства ReadTimeout и WriteTimeout. Возможно, время ожидания потока истекло?   -  person Danexxtone    schedule 08.07.2011
comment
Я попытался установить ReadTimeout и получил исключение: таймауты не поддерживаются в этом потоке.   -  person toby    schedule 08.07.2011
comment
Можете ли вы прояснить несколько вещей: Почему байтовый массив? Нет ли потока из загрузки, который можно было бы напрямую передать img.SetSource? Вы уверены, что загружаемые png-файлы имеют размер эскиза или вы загружаете изображения большего размера, которые масштабируются с помощью элемента управления изображением? Это миниатюры фотографий?   -  person AnthonyWJones    schedule 08.07.2011
comment
Я загружаю несколько изображений за один запрос, поэтому я не могу передать запрос напрямую в img.SetSource (отсюда и массив байтов). Изображения полноразмерные, поскольку я кэширую их для основного кадра просмотра, но это отсканированные документы, и они не очень большие (в большинстве случаев файлы размером от 100 до 200 КБ). Я бы ожидал какой-то ошибки нехватки памяти, если проблема связана с слишком большим объемом данных.   -  person toby    schedule 08.07.2011
comment
Не могли бы вы показать больше кода, связанного с самой загрузкой и обработкой? Есть еще несколько вопросов, и на них можно будет быстрее ответить, посмотрев код.   -  person Danexxtone    schedule 08.07.2011


Ответы (2)


Я думаю, что процитировать ответ, предоставленный Microsoft в приведенном выше отчете об ошибке, стоит, поскольку он очень краток и описывает проблему, а также предоставляет рекомендуемое решение:

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

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

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

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

person Xcalibur    schedule 04.08.2011

Я отправил в Microsoft отчет об этой проблеме: Исключение Catastrophic Failure возникает после загрузки слишком большого количества объектов BitmapImage из потока.

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

person toby    schedule 18.07.2011