【发布时间】:2018-10-03 23:26:43
【问题描述】:
我正在处理一个图像处理项目,但遇到了一个问题。
我有一个方法,它将(图像的)流作为输入并返回包含所提供图像的子部分的流列表:
public List<System.IO.Stream> ImageProcessing(System.IO.Stream input){
Bitmap inputAsBitmap = new Bitmap(input);
// --- Applying miscellaneous filters ---
List<Bitmap> subParts = GetSubParts(inputAsBitmap);
inputAsBitmap.Dispose();
List<System.IO.Stream> streams = new List<Stream>();
for(int i = 0; i < subParts.Count; i++){
MemoryStream memoryStream = new MemoryStream();
subParts[i].Save(memoryStream, ImageFormat.Jpeg);
streams.Add(memoryStream);
subParts[i].Dispose();
}
return streams;
}
当我通过 OpenFileDialog 选择图像手动调用此方法时,一切正常:
using (Stream imageStream = File.OpenRead(filename)){
List<Stream> streams = ImageProcessing(imageStream);
for(int i = 0; i < streams.Count; i++){
System.Drawing.Image.FromStream(streams[i]).Save();
streams[i].Dispose();
}
}
但是当我尝试选择一个文件夹并在 for 循环中调用它时,每个图像都属于它,OutOfMemoryException 被抛出:
for(int i = 0; i < filenames.Count; i++){
using (Stream imageStream = File.OpenRead(filenames[i])){
List<Stream> streams = ImageProcessing(imageStream);
for(int j = 0; j < streams.Count; j++){
System.Drawing.Image.FromStream(streams[j]).Save();
streams[j].Dispose();
}
}
}
在调查时,我发现执行大约需要 20 毫秒的指令块可以清理内存,从而防止引发异常:
for(int i = 0; i < filenames.Count; i++){
// --- A block of instructions placed here will prevent the exception ---
using (Stream imageStream = File.OpenRead(filenames[i])){
// -- Same code as above ---
}
}
此外,在多点检查内存时(通过使用Process.GetCurrentProcess().PrivateMemorySize64 或System.GC.GetTotalMemory()),处理Bitmap 和Stream 似乎不会改变与已用内存量有关的任何事情。
关于我如何摆脱这个OutOfMemoryException 的任何提示?
对于在 for 循环中调用 ImageProcessing 方法时内存没有被清理的事实,你有什么解释吗?而它在两次调用之间手动完成?
编辑:
这是我现在拥有的,但仍然无法正常工作:
for(int i = 0; i < filenames.Count; i++){
using (Stream imageStream = File.OpenRead(filenames[i])){
List<Stream> streams = ImageProcessing(imageStream);
for(int j = 0; j < streams.Count; j++){
using (var image = System.Drawing.Image.FromStream(streams[j]))
image.Save();
streams[j] = null;
//System.GC.Collect();
}
}
}
//System.GC.Collect();
【问题讨论】:
-
文件夹中选择了多少个文件?所有这些图像的大小是多少?进程是否用 AnyCPU 编译(即它是 64 位进程)?
-
看起来您确实在构建一个 AnyCPU 应用程序,但默认为 32 位。
-
streams[i]真的是MemoryStream吗?如果是这样,那么处理它实际上不会释放任何内存,请参阅referencesource.microsoft.com/#mscorlib/system/io/…。您需要明确删除对它的任何引用,以便它可以被垃圾收集。 -
切换到 64 位只是推迟问题 - 当您修复泄漏时,它应该能够以 3GB 运行。而且您最好不要在服务中运行此代码。
标签: c#