【发布时间】:2015-08-23 00:32:52
【问题描述】:
背景信息
我使用 Windows 窗体 (C#) 开发了一个桌面应用程序,用于扫描、预览和保存图像。 扫描时的应用行为如下:
- 扫描 n 张图片
- 为每个图像获取一个位图并将其存储在一个临时文件中
- 将调整大小的缩略图显示为预览
图像内存管理:可压缩图像
为了管理内存使用,我创建了一个 CompressibleImage 类,它封装了位图文件并在 FileStream 上读取/写入图像文件。当应用程序不再需要图像时,会将其写入文件流。当应用程序需要图像(即用户双击缩略图)时,会从流中创建一个位图文件。以下是 CompressibleImage 的 主要方法:
/// Gets the uncompressed image. If the image is compressed, it will be uncompressed
public Image GetDecompressedImage()
{
if (decompressedImage == null)
{
// Read Bitmap from file stream
stream.Seek(0, SeekOrigin.Begin);
decompressedImage = new Bitmap(stream);
}
return decompressedImage;
}
/// Clears the uncompressed image, leaving the compressed one in memory.
public void ClearDecompressedImage()
{
// If Bitmap file exists, write it to file and dispose it
if (decompressedImage != null)
{
if (stream == null)
{
stream = new FileStream(FileStreamPath, FileMode.Create);
}
decompressedImage.Save(stream, format);
// The Dispose() call does not solve the issue
// decompressedImage.Dispose();
decompressedImage = null;
}
}
/// <summary>
/// Class destructor. It disposes the decompressed image (if this exists),
/// closes the stream and delete the temporary file associated.
/// </summary>
~CompressibleImage()
{
if (decompressedImage != null)
{
decompressedImage.Dispose();
}
if(stream != null)
{
stream.Close();
File.Delete(stream.Name);
stream.Dispose();
}
}
应用级别
应用程序主要在扫描方法和保存过程中使用 CompressibleImage 创建图像文件。 扫描方法工作正常,基本上:
- 从扫描仪获取位图
- 从扫描的位图创建 CompressibleImage
- 将位图写入文件流
save 方法在我的机器上运行良好,其行为如下: 1. 对于每个 CompressibleImage 从流中解压缩(读取和构建)位图 2. 保存图片 3. 压缩图片
这里是保存方法:
private void saveImage_button_Click(object sender, EventArgs e)
{
if (Directory.Exists(OutputPath) == false && File.Exists(OutputPath) == false)
{
Directory.CreateDirectory(OutputPath);
}
ListView.CheckedListViewItemCollection checkedItems = listView1.CheckedItems;
if(checkedItems.Count > 0)
{
for (int i = 0; i < checkedItems.Count; ++i)
{
int index = checkedItems[i].Index;
Bitmap image = (Bitmap)compressibleImageList.ElementAt(index).GetDecompressedImage();
try
{
image.Save(OutputPath + index.ToString() +
Module.PNG_FORMAT, ImageFormat.Png);
compressibleImageList.ElementAt(index).ClearDecompressedImage();
progressForm.Increment();
image = null;
}
catch (Exception ex) {
...
}
}
}
}
问题描述
在我的机器上,应用程序运行良好。没有内存泄漏,scan 和 save 方法可以顺利完成工作,并且内存使用合理(扫描 100 张纸,选择小于
问题是,当我尝试在其他机器上测试应用程序时,垃圾收集器没有释放内存,导致在这两种方法的执行过程中以及当图像相当高(> 40)。当我尝试解压缩(读取)图像时,CompressibleImage.GetDecompressedImage() 方法中会引发异常:
decompressedImage = new Bitmap(stream);
虽然我知道 GC 会随机清理内存,但在这种情况下,它似乎甚至没有运行,实际上只有在我关闭应用程序时才会释放内存。
在类似的机器上可能会有这种不同的行为吗?
系统信息
以下是有关测试环境的一些信息。两台机器都有:
- 处理器:Intel i7 2.30GHz
- 内存:8GB
- 类型:64 位
- 操作系统:Windows 7 Pro SP 1
【问题讨论】:
-
不是说这是问题所在,而是你的析构函数实现不对。您不应该在其中引用其他托管对象,因为不能保证它们仍然可以访问。研究实现
IDisposable接口。请参阅here 了解更多信息。
标签: c# memory-leaks bitmap garbage-collection