Исключение из-за нехватки памяти при загрузке изображений - PullRequest
3 голосов
/ 31 января 2011

Я использую следующий фрагмент кода для загрузки изображений в виде миниатюр в элемент управления FlowLayoutPanel.К сожалению, я получаю исключение OutOfMemory.

Как вы уже догадались, утечка памяти обнаружена в строке

 Pedit.Image = System.Drawing.Image.FromStream(fs)

Так как я могу оптимизировать следующий код?

 Private Sub LoadImagesCommon(ByVal FlowPanel As FlowLayoutPanel, ByVal fi As FileInfo)
        Pedit = New DevExpress.XtraEditors.PictureEdit
        Pedit.Width = txtIconsWidth.EditValue
        Pedit.Height = Pedit.Width / (4 / 3)
        Dim fs As System.IO.FileStream
        fs = New System.IO.FileStream(fi.FullName, IO.FileMode.Open, IO.FileAccess.Read)
        Pedit.Image = System.Drawing.Image.FromStream(fs)
        fs.Close()
        fs.Dispose()
        Pedit.Properties.SizeMode = DevExpress.XtraEditors.Controls.PictureSizeMode.Zoom

        If FlowPanel Is flowR Then
            AddHandler Pedit.MouseClick, AddressOf Pedit_MouseClick
            AddHandler Pedit.MouseEnter, AddressOf Pedit_MouseEnter
            AddHandler Pedit.MouseLeave, AddressOf Pedit_MouseLeave
        End If

        FlowPanel.Controls.Add(Pedit)
    End Sub

Обновление: Проблема возникает при загрузке нескольких изображений (3264x2448 пикселей при 300 dpi - каждое изображение имеет размер около 3 МБ)

Ответы [ 4 ]

5 голосов
/ 31 января 2011

Документация для Image.FromFile (которая относится к вашему FromStream) гласит, что будет выдано OutOfMemoryException, если файл не является допустимым форматом изображения или если GDI + не поддерживает формат пикселей.Возможно ли, что вы пытаетесь загрузить неподдерживаемый тип изображения?

Кроме того, в документации для Image.FromStream говорится, что вы должны держать поток открытым в течение всего времени жизни изображения, так что даже если ваш код загрузилизображение вы, вероятно, получите ошибку, потому что вы закрываете файл, пока изображение все еще активно.Смотри http://msdn.microsoft.com/en-us/library/93z9ee4x.aspx.

3 голосов
/ 01 февраля 2011

Вы можете решить эту проблему за несколько шагов:

  • Чтобы освободиться от файловой зависимости, вам необходимо скопировать изображения. Реально рисуя его в новом растровом изображении, вы не можете просто скопировать его.
  • , поскольку вам нужны миниатюры, а ваши исходные растровые изображения довольно большие, объедините это с уменьшением изображений.
3 голосов
/ 01 февраля 2011

Пара мыслей:

Прежде всего, как сказал Джим, при использовании Image.FromStream поток должен оставаться открытым в течение всего времени жизни образа, как отмечено на странице MSDN.Поэтому я бы предложил скопировать содержимое файла в MemoryStream и использовать последний для создания экземпляра Image.Таким образом, вы можете освободить дескриптор файла как можно скорее.

Во-вторых, используемые вами изображения довольно большие (несжатые, так как они будут существовать в памяти, Width x Height x BytesPerPixel).Предполагая, что контекст, в котором вы их используете, может позволить уменьшить их размер, рассмотрите возможность их изменения размера и, возможно, кэширование версий с измененным размером где-то для дальнейшего использования.

Наконец, не забудьте утилизировать изображение и поток,они больше не нужны.

0 голосов
/ 11 января 2012

У меня была такая же проблема. Ответ Джима Мишеля привел меня к тому, что загрузка невинного файла .txt была причиной. Вот мой метод на случай, если кому-то будет интересно.

Вот мой метод:

/// <summary>
/// Loads every image from the folder specified as param.
/// </summary>
/// <param name="pDirectory">Path to the directory from which you want to load images.  
/// NOTE: this method will throws exceptions if the argument causes 
/// <code>Directory.GetFiles(path)</code> to throw an exception.</param>
/// <returns>An ImageList, if no files are found, it'll be empty (not null).</returns>
public static ImageList InitImageListFromDirectory(string pDirectory)
{
    ImageList imageList = new ImageList();

    foreach (string f in System.IO.Directory.GetFiles(pDirectory))
    {
        try
        {
            Image img = Image.FromFile(f);
            imageList.Images.Add(img);
        }
        catch
        {
            // Out of Memory Exceptions are thrown in Image.FromFile if you pass in a non-image file.
        }
    }

    return imageList;
}
...