尽管使用 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
属性 并避免创建和处理 Image
s。
最主要的是尽量减少重复代码的数量,以便您 Dont Repeat Yourself。 Next 和 Previous 的代码将几乎相同。
当我向用 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
属性 并避免创建和处理 Image
s。
最主要的是尽量减少重复代码的数量,以便您 Dont Repeat Yourself。 Next 和 Previous 的代码将几乎相同。