2014-02-24 51 views
2

我有一个WPF应用程序,我通过使用TiffBitmapEncoder将它们转换为TIFF图像来保存数百个BitmapSource中的几个。但是,我有这种奇怪的内存消耗,这往往是抛出内存不足的例外。TiffBitmapEncoder,在C#/ WPF中导致内存不足异常的内存错误

注:

  • 我已经安装的RAM 8GB。

    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); 
        } 
    } 
    

    这里是我的记忆的屏幕截图:

  • 图像尺寸从10×10到300×300像素(相当小)

这里是工作的代码变化No memory exception

现在,如果我克隆BitmapSource(即使只是一次),然后我得到这个巨大的内存分配导致内存不足E xception。

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); 
    } 
} 

这是我记忆中的第二个代码示例

Memory exception

有谁知道这可能是造成这个问题以及如何解决它的截图?

不同之处在于第一个示例中的BitmapSource已呈现到屏幕上,第二个示例中没有。我怀疑是这可能是与GPU以及可能是硬件加速,其中有某种错误的而第二个是在CPU上进行转换的调度......

尝试:

  • 试过SaveBitmapSource()没有运气
+0

有没有什么处理source2? – BlueMonkMN

+0

BitmapSource不实现IDisposable –

+0

如果在函数末尾添加'GC.Collect()'会影响内存使用,那么好奇。不是一个解决方案,而是一个诊断步骤。 – BlueMonkMN

回答

1

我已经解决了这个问题后,调用GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true);通过调用

GC.WaitForPendingFinalizers(); 

之后SaveBitmapSource()

所以我的猜测是,里面有BitmapSource和/或BitmapEncoder一些非托管资源这是不被释放,直到最终化方法已经运行...

0

我很高兴能解决问题。但我不相信这是正确的解决方案。 我看到你只用一个参数调用BitmapFrame.Create()。你可能想在该更仔细地看看..

尝试使用BitmapCacheOption.None标志 - 默认情况下它可能无故被缓存每个位图的内存:

BitmapFrame.Create(源,BitmapCreateOptions .PreservePixelFormat,BitmapCacheOption。没有);

2

你必须使用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;