TiffBitmapEncoder,内存错误导致C#/WPF中内存不足异常
我有一个WPF应用程序,通过使用TiffBitmapEncoder将数百个BitMapSource转换为TIFF图像,从而节省了它们。然而,我有一个奇怪的内存消耗,它经常抛出内存不足异常TiffBitmapEncoder,内存错误导致C#/WPF中内存不足异常,c#,wpf,memory,out-of-memory,bitmapencoder,C#,Wpf,Memory,Out Of Memory,Bitmapencoder,我有一个WPF应用程序,通过使用TiffBitmapEncoder将数百个BitMapSource转换为TIFF图像,从而节省了它们。然而,我有一个奇怪的内存消耗,它经常抛出内存不足异常 static BitmapSource source2 = null; static void SaveBitmapSource(BitmapSource bitmapSource) { if (source2 == null) { source2 = bitmapSource.
static BitmapSource source2 = null;
static void SaveBitmapSource(BitmapSource bitmapSource)
{
if (source2 == null)
{
source2 = bitmapSource.Clone();
}
TiffBitmapEncoder encoder = new TiffBitmapEncoder();
encoder.Compression = TiffCompressOption.Zip;
BitmapFrame frame = BitmapFrame.Create(source2);
encoder.Frames.Add(frame);
using (MemoryStream ms = new MemoryStream())
{
encoder.Save(ms);
}
}
注:
- 我安装了8GB的ram
- 图像大小从10x10到300x300像素不等(非常小)
static void SaveBitmapSource(BitmapSource bitmapSource)
{
TiffBitmapEncoder encoder = new TiffBitmapEncoder();
encoder.Compression = TiffCompressOption.Zip;
BitmapFrame frame = BitmapFrame.Create(bitmapSource);
encoder.Frames.Add(frame);
using (MemoryStream ms = new MemoryStream())
{
encoder.Save(ms);
}
}
这是我记忆的屏幕截图:
现在,如果我克隆BitmapSource(即使只克隆一次),那么我会得到巨大的内存分配,导致内存不足异常
static BitmapSource source2 = null;
static void SaveBitmapSource(BitmapSource bitmapSource)
{
if (source2 == null)
{
source2 = bitmapSource.Clone();
}
TiffBitmapEncoder encoder = new TiffBitmapEncoder();
encoder.Compression = TiffCompressOption.Zip;
BitmapFrame frame = BitmapFrame.Create(source2);
encoder.Frames.Add(frame);
using (MemoryStream ms = new MemoryStream())
{
encoder.Save(ms);
}
}
这是我记忆中第二个代码示例的屏幕截图
有人知道是什么原因导致了这种情况,以及如何修复它吗
不同之处在于,第一个示例中的BitmapSource已呈现到屏幕上,而第二个示例中的BitmapSource尚未呈现到屏幕上。我怀疑这可能与GPU和调度程序有关,可能是硬件加速了转换,而第二个是在CPU上完成的,其中存在某种bug
尝试:
- 尝试调用
GC.Collect(GC.MaxGeneration,GCCollectionMode.Forced,true)在
之后没有运气SaveBitmapSource()
GC.WaitForPendingFinalizers();
就在SaveBitmapSource()之后
所以我猜在BitmapSource
和/或BitmapEncoder
中有一些非托管资源,直到Finalize方法运行后才发布…我很高兴这解决了问题。但我不相信这是正确的解决办法。
我看到您正在使用一个参数调用BitmapFrame.Create()。你可能想更仔细地看一下
尝试使用BitmapCacheOption.None标志-默认情况下,它可能会无缘无故地在内存中缓存每个位图:
创建(源,BitmapCreateOptions.PreservePixelFormat,BitmapCacheOption.None) 您必须使用filestream来减少内存使用
BitmapDecoder decoder;
using (Stream appendToOutput = File.Open(files[0], FileMode.Open, FileAccess.Read, FileShare.Read))
{
decoder = BitmapDecoder.Create(appendToOutput, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.None);
using (Stream output = File.Open(outputFile, FileMode.Create, FileAccess.Write))
{
TiffBitmapEncoder childEncoder = new TiffBitmapEncoder();
if(Path.GetExtension(files[0]).Replace(".", "") == ScanningImageFormat.Jpeg) {
childEncoder.Compression = TiffCompressOption.Zip;
} else {
childEncoder.Compression = TiffCompressOption.Ccitt4;
}
foreach (BitmapFrame frm in decoder.Frames)
{
childEncoder.Frames.Add(frm);
}
List<Stream> imageStreams = new List<Stream>();
try
{
for (int i = 1; i < files.Count; i++)
{
string sFile = files[i];
BitmapFrame bmp = null;
Stream original = File.Open(sFile, FileMode.Open, FileAccess.Read);
imageStreams.Add(original);
bmp = BitmapFrame.Create(original, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.None);
childEncoder.Frames.Add(bmp);
}
childEncoder.Save(output);
}
finally
{
try
{
foreach (Stream s in imageStreams)
{
s.Close();
}
}
catch { }
}
}
}
decoder = null;
位图解码器;
使用(Stream appendToOutput=File.Open(文件[0],FileMode.Open,FileAccess.Read,FileShare.Read))
{
解码器=BitmapDecoder.Create(appendToOutput,BitmapCreateOptions.PreservePixelFormat,BitmapCacheOption.None);
使用(Stream output=File.Open(outputFile,FileMode.Create,FileAccess.Write))
{
TiffBitmapEncoder childEncoder=新的TiffBitmapEncoder();
if(Path.GetExtension(文件[0]).Replace(“.”,”)==ScanningImageFormat.Jpeg){
childEncoder.Compression=TiffCompressOption.Zip;
}否则{
childEncoder.Compression=TiffCompressOption.Ccitt4;
}
foreach(解码器中的位图帧frm.Frames)
{
childEncoder.Frames.Add(frm);
}
List imageStreams=新列表();
尝试
{
对于(int i=1;i
是否有任何处理source2的方法?如果在函数末尾添加GC.Collect()
会影响内存使用,则BitmapSource不会实现IDisposableCurious。不是作为解决方案,而是作为一个诊断步骤。我尝试了GC.Collect(GC.MaxGeneration,GCCollectionMode.Forced,true);但是没有任何区别这是一个尖峰,不是一步。所以这当然不是内存泄漏。与GC也没有任何关系,这都是非托管代码。阻止你使用所有优秀硬件的传统错误是强迫你的程序以32位模式运行。使用Project+属性、构建选项卡、平台目标设置修复。