尽管使用 Image.Dispose,图像查看器内存不足

Out of memory in image viewer despite using Image.Dispose

当我向用 C# 编码的图像查看器添加“下一个”和“上一个”导航选项时,当我按“下一步”大约 20 次左右时,Visual Studio 告诉我进程 运行 内存不足。它在任何有很多的文件夹中执行此操作,即使它们的图像文件大小都很小

我得到:

An unhandled exception of type 'System.OutOfMemoryException' occurred in System.Drawing.dll Additional information: Out of memory.

这是我正在使用的代码

private void next_Click(object sender, EventArgs e)
{
    string[] foldernm = Directory.GetFiles(Path.GetDirectoryName(lfoto_file.FileName));
    _pictureIndex++;
    if (_pictureIndex >= foldernm.Length)
    {
        _pictureIndex = 0;
    }
    ibread_img.Image.Dispose();
    ibread_img.Image = Image.FromFile(foldernm[_pictureIndex]);
}

现在如您所见,我有 ibread_img.Image.Dispose(); 在那里,因为我已经搜索过这个和其他人说使用那个,但它不起作用而且我仍然遇到同样的问题,中断 -点确认代码正在 运行 所以我很困惑为什么它仍然 运行 内存不足。我循环浏览的图像并不大。我已经尝试了所有我能找到的方法,包括清空之前加载的图像、手动调用垃圾收集器,但似乎没有任何效果。我不是最擅长 C# 的,所以该代码中可能存在可怕的错误或缺陷,但我不知道,关于如何解决这个问题有什么想法吗?

感谢 LarsTech 和 Plutonix 指出我的错误。这个新代码现在可以正常工作了:

private void next_Click(object sender, EventArgs e)
    {
        var filteredFiles = Directory.EnumerateFiles(Path.GetDirectoryName(lfoto_file.FileName))
            .Where(file => file.ToLower().EndsWith("jpg") || file.ToLower().EndsWith("png") || file.ToLower().EndsWith("gif") || file.ToLower().EndsWith("bmp") || file.ToLower().EndsWith("tiff") || file.ToLower().EndsWith("ico"))
            .ToList();
        _pictureIndex++;
        if (_pictureIndex >= filteredFiles.Count)
        {
            _pictureIndex = 0;
        }
        ibread_img.Image.Dispose();
        ibread_img.Image = Image.FromFile(filteredFiles[_pictureIndex]);
        init();
    }

我只需要过滤出正确的格式。

您可以采取一些措施来改进查看器。首先,您每次都在重新创建图像文件列表;你每次加载所有这些只是为了访问下一个,你不必创建图像来显示它。

// class level vars
int picIndex = 0;
IEnumerable<string> files;
int filesCount;
string picPath;
static string[] imgExts = {".png", ".jpg",".gif"};

既然你提到了 Next 和 Previous 按钮,你一定在其他地方有几乎相同的代码。这将消除重复,下一步:

ShowImage(picIndex);

picIndex+=1;
if (picIndex >= filesCount)
    picIndex = 0;

然后显示所需图像的方法:

private void ShowImage(int Index)
{ 
    // create image list if needed (once)
    if (files == null)
    { 
        files = new DirectoryInfo(picPath).EnumerateFiles().
            Where(q => imgExts.Contains(q.Extension.ToLowerInvariant())).
            Select( z => z.FullName);

        filesCount = files.Count();
    }

    string thisFile = files.ElementAt(Index);

    // no need to dispose an image if you never create one          
    pb2.ImageLocation = thisFile;
    lblImgName.Text = Path.GetFileName(thisFile);
}

而是每次(在 2 个地方)创建文件列表,这是一次,而不是加载所有文件的列表,这将它保留为 IEnumerable 以根据需要获取它们.它也适用于 FileInfo,不区分大小写,主要是为了说明一种不同的方式,如果您愿意,可以按创建日期对它们进行排序 (OrderBy)。

最后,给定完整路径和文件名,您可以使用 .ImageLocation 属性 并避免创建和处理 Images。

最主要的是尽量减少重复代码的数量,以便您 Dont Repeat Yourself。 Next 和 Previous 的代码将几乎相同。