Получение 'из памяти' исключение в этой относительно простой программе

Вот мой класс Picture.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Drawing;

namespace SharpLibrary_MediaManager
{
    public class Picture:BaseFile
    {
        public int Height { get; set; }
        public int Width { get; set; }
        public Image Thumbnail { get; set; }

        /// <summary>
        /// Sets file information of an image from a given image in the file path.
        /// </summary>
        /// <param name="filePath">File path of the image.</param>
        public override void  getFileInformation(string filePath)
        {
            FileInfo fileInformation = new FileInfo(filePath);
            if (fileInformation.Exists)
            {
                Name = fileInformation.Name;
                FileType = fileInformation.Extension;
                Size = fileInformation.Length;
                CreationDate = fileInformation.CreationTime;
                ModificationDate = fileInformation.LastWriteTime;
                Height = calculatePictureHeight(filePath);
                Width = calculatePictureWidth(filePath);                
            }
        }

        public override void getThumbnail(string filePath)
        {            
            Image image = Image.FromFile(filePath);
            Thumbnail = image.GetThumbnailImage(40, 40, null, new IntPtr());            
        }

        private int calculatePictureHeight(string filePath)
        {
            var image = Image.FromFile(filePath);
            return image.Height;
        }

        private int calculatePictureWidth(string filePath)
        {
            var image = Image.FromFile(filePath);
            return image.Width;
        }
    }
}

И здесь, я использую тот класс для получения по запросу информации из каждого файла в данной папке:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace SharpLibrary_MediaManager
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        string folderPath = @"D:\Images\PictureFolder";

        private void button1_Click(object sender, EventArgs e)
        {
            DirectoryInfo folder = new DirectoryInfo(folderPath);
            List<Picture> lol = new List<Picture>();
            foreach (FileInfo x in folder.GetFiles())
            {
                Picture picture = new Picture();
                picture.getFileInformation(x.FullName);
                lol.Add(picture);
            }

            MessageBox.Show(lol[0].Name);
        }
    }
}

Я добираюсь Из исключения Памяти, и я действительно не знаю почему. Это - первый раз, когда я делаю что-то вроде этого так, что я довольно плохо знаком с обработкой пакетного файла и т.д.

Какие-либо парни справки?:)

Править: Я открыл Task Manager для наблюдения использования памяти и когда я нажимаю Button для выполнения метода, я замечаю свои увеличения использования памяти на 100 МБ ~ каждую секунду.

Редактирование 2: В моей папке у меня есть приблизительно 103 изображения, при этом каждое изображение ~100kb. Мне нужно решение, где не имеет значения, сколько изображений находится в папке. Кто-то рекомендовал открыть изображение, делая мое волшебство, затем закройте его. Я действительно не понимаю то, под чем он подразумевал 'близко'.

Кто-то может рекомендовать другой подход?:)

Редактирование 3: Все еще добираясь из исключения памяти, я изменил код в Picture.cs на основе рекомендаций, но я вне идей. Какая-либо справка?

public override void  getFileInformation(string filePath)
        {
            FileInfo fileInformation = new FileInfo(filePath);

            using (var image = Image.FromFile(filePath))
            {
                if (fileInformation.Exists)
                {
                    Name = fileInformation.Name;
                    FileType = fileInformation.Extension;
                    Size = fileInformation.Length;
                    CreationDate = fileInformation.CreationTime;
                    ModificationDate = fileInformation.LastWriteTime;
                    Height = image.Height;
                    Width = image.Width;
                }
            }
        }

Кроме того, я должен открыть новый вопрос теперь, когда этот вырос немного?

6
задан 5 February 2010 в 15:02
поделиться

10 ответов

Вы не вызываете Dispose on your Image instances (Утилизировать на экземплярах изображений). Также создайте изображение один раз и затем извлеките данные.

См. также:

http://msdn.microsoft.com/en-us/library/8th8381z.aspx

EDIT Если бы вы скопировали ваш код и протестировали его с помощью моей библиотеки изображений. Мой Август FileSize составляет 2-3 Мб за Файл. Я выполнил вашу программу и она сделала именно то, что должна. ГК сделал именно то, что я ожидал.

Память вашей программы всегда была около 11-35 МБ Private Work Set, размер Commit Size был стабилен на уровне 43 МБ.

Я прервал работу программы после 1156 файлов с общим размером картинки 2,9 ГБ.

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

Вот вывод и код моей программы:

1133: Total Size = 2.842,11 MB
1134: Total Size = 2.844,88 MB
1135: Total Size = 2.847,56 MB
1136: Total Size = 2.850,21 MB
1137: Total Size = 2.853,09 MB
1138: Total Size = 2.855,86 MB
1139: Total Size = 2.858,59 MB
1140: Total Size = 2.861,26 MB
1141: Total Size = 2.863,65 MB
1142: Total Size = 2.866,15 MB
1143: Total Size = 2.868,52 MB
1144: Total Size = 2.870,93 MB
1145: Total Size = 2.873,64 MB
1146: Total Size = 2.876,15 MB
1147: Total Size = 2.878,84 MB
1148: Total Size = 2.881,92 MB
1149: Total Size = 2.885,02 MB
1150: Total Size = 2.887,78 MB
1151: Total Size = 2.890,57 MB
1152: Total Size = 2.893,55 MB
1153: Total Size = 2.896,32 MB
1154: Total Size = 2.898,92 MB
1155: Total Size = 2.901,48 MB
1156: Total Size = 2.904,02 MB

Sourcecode:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Drawing;

namespace SharpLibrary_MediaManager
{
    public abstract class BaseFile
    {
        public string Name { get; set; }
        public string FileType { get; set; }
        public long Size { get; set; }
        public DateTime CreationDate { get; set; }
        public DateTime ModificationDate { get; set; }

        public abstract void getFileInformation(string filePath);

    }


    public class Picture : BaseFile
    {
        public int Height { get; set; }
        public int Width { get; set; }
        public Image Thumbnail { get; set; }

        public override void getFileInformation(string filePath)
        {
            FileInfo fileInformation = new FileInfo(filePath);

            using (var image = Image.FromFile(filePath))
            {
                if (fileInformation.Exists)
                {
                    Name = fileInformation.Name;
                    FileType = fileInformation.Extension;
                    Size = fileInformation.Length;
                    CreationDate = fileInformation.CreationTime;
                    ModificationDate = fileInformation.LastWriteTime;
                    Height = image.Height;
                    Width = image.Width;
                    Thumbnail = image.GetThumbnailImage(40, 40, null, new IntPtr());
                }
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            string folderPath = @"C:\Users\arthur\Pictures";

            DirectoryInfo folder = new DirectoryInfo(folderPath);
            List<Picture> lol = new List<Picture>();
            double totalFileSize = 0;
            int counter = 0;
            foreach (FileInfo x in folder.GetFiles("*.jpg", SearchOption.AllDirectories))
            {
                Picture p = new Picture();
                p.getFileInformation(x.FullName);
                lol.Add(p);
                totalFileSize += p.Size;
                Console.WriteLine("{0}: Total Size = {1:n2} MB", ++counter, totalFileSize / 1048576.0);
            }

            foreach (var p in lol)
            {
                Console.WriteLine("{0}: {1}x{2} px", p.Name, p.Width, p.Height);
            }
        }
    }
}
14
ответ дан 8 December 2019 в 02:52
поделиться

Вы должны освободить ресурсы, используемые при открытии объекта Image .

Вы можете вызвать Dispose или создать свой образ с помощью оператора Используя

например.

public override void getThumbnail(string filePath)
{
    using (Image image = Image.FromFile(filePath))
    {
        Thumbnail = image.GetThumbnailImage(40, 40, null, new IntPtr());
    }
}

А поскольку ваш класс содержит Image , вам следует реализовать интерфейс IDisposable , поэтому вы также можете использовать его в операторе using .

6
ответ дан 8 December 2019 в 02:52
поделиться

Несколько проблем провожу сразу. Во-первых, вы загружаете каждое изображение дважды с последующими вызовами CalculatePictureWidth и CalculatePictureHeight. Во-вторых, похоже, что вы на самом деле ничего не делаете с миниатюрой. В-третьих, вы должны вызвать Dispose для экземпляров Image, как только вы закончите сбор информации от них.

5
ответ дан 8 December 2019 в 02:52
поделиться

Файл образа содержит дескриптор большого блока неуправляемых данных. Эти данные необходимо удалить, и вы делаете это, явно вызывая Image.Dispose. Поскольку вы не вызываете Dispose в методах calculatePictureHeight и calculatePictureWidth, файлы изображений хранятся в памяти, что вызывает исключения OOM.

[Обновление]: Возможно, мне будет полезно немного больше информации, почему это происходит на самом деле. В конце концов, разве не существует GC, который убирает за нас этот беспорядок? Да, есть, и GC довольно эффективен. В конечном итоге он также очистит объекты, которые нам пришлось утилизировать.

Класс Image содержит финализатор. Этот финализатор гарантирует, что все ресурсы будут очищены, даже если вы забудете вызвать Dispose. Однако здесь происходит то, что у вас заканчивается память, что немедленно запускает GC.Collect. Во время этого сбора сборщик мусора находит все ваши изображения, на которые нет ссылок. Однако, поскольку сборщик мусора не запускает метод финализатора немедленно, все ваши объекты повышаются до Gen1 (они хранятся в памяти), как и все ваши ресурсы (собственная память). Таким образом, даже после того, как сборщик мусора сработал, памяти все еще недостаточно, и вы получите исключение OOM.

Вот почему вы всегда должны удалять объекты, реализующие IDisposable.

3
ответ дан 8 December 2019 в 02:52
поделиться

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

Проверьте метод Image.Dispose ().

2
ответ дан 8 December 2019 в 02:52
поделиться

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

1
ответ дан 8 December 2019 в 02:52
поделиться

Я сильно подозреваю, что то, что вы видите, является странностью предсказания ветвей, а не чем-то связанным с кэшированием. В частности, на множестве ЦП прогнозирование ветвей не работает (а также | вообще), когда и источник, и цель ветви находятся в одной строке кэша. Размещение достаточного количества кода внутри цикла (даже НОП), чтобы получить источник и цель в различные строки кэша, даст существенное улучшение скорости.

-121--2724940-

ToShortDateString () не поддерживается Linq to SQL http ://msdn.microsoft.com/en-us/library/bb882657.aspx

-121--4543543-

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

1
ответ дан 8 December 2019 в 02:52
поделиться

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

1
ответ дан 8 December 2019 в 02:52
поделиться

Сможете ли вы это сделать?

public class Picture:BaseFile
{
    public int Height { get; set; }
    public int Width { get; set; }
    public Image Thumbnail { get; set; }

    /// <summary>
    /// Sets file information of an image from a given image in the file path.
    /// </summary>
    /// <param name="filePath">File path of the image.</param>
    public override void  getFileInformation(string filePath)
    {
        FileInfo fileInformation = new FileInfo(filePath);
        if (fileInformation.Exists)
        {
            /*
            Name, FileType, Size, etc
            */
            using (Image image = Image.FromFile(filePath))
            {
                Height = image.Height;
                Width = image.Width;
                Thumbnail = image.GetThumbnailImage(40, 40, new Image.GetThumbnailImageAbort(ThumbnailCallback), default(IntPtr));
            }
        }
    }

    public bool ThumbnailCallback()
    {
        return false;
    }
}
0
ответ дан 8 December 2019 в 02:52
поделиться

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

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

[Edit] удалила часть ответа, которая, по мнению других, неуместна; Я предположил, что класс изображения - это класс изображения XNA.

-1
ответ дан 8 December 2019 в 02:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: