我有一个WPF应用程序,我通过使用TiffBitmapEncoder将它们转换为TIFF图像来保存数百个BitmapSource。但是,我有这种奇怪的内存消耗,往往会导致内存不足。
注意:
这是有效的代码:
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已渲染到屏幕而第二个示例中没有。我怀疑这可能与GPU和Dispatcher有关,可能是硬件加速转换,而第二个是在CPU上完成的,那里有某种bug ......
尝试:
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true);
没有运气SaveBitmapSource()
答案 0 :(得分:2)
你必须使用文件流来减少内存使用;
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;
答案 1 :(得分:1)
我通过调用
解决了这个问题GC.WaitForPendingFinalizers();
在SaveBitmapSource()
之后。
所以我的猜测是BitmapSource
和/或BitmapEncoder
内部有一些非托管资源未被释放,直到运行Finalize方法......
答案 2 :(得分:0)
我很高兴解决了这个问题。但我不相信这是正确的解决办法。 我看到你只用一个参数调用BitmapFrame.Create()。你可能想更仔细地看一下......
尝试使用BitmapCacheOption.None标志 - 默认情况下,它可能无缘无故地缓存内存中的每个位图:
BitmapFrame.Create(source,BitmapCreateOptions.PreservePixelFormat,BitmapCacheOption.None);