Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/kubernetes/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
TiffBitmapEncoder,内存错误导致C#/WPF中内存不足异常_C#_Wpf_Memory_Out Of Memory_Bitmapencoder - Fatal编程技术网

TiffBitmapEncoder,内存错误导致C#/WPF中内存不足异常

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.

我有一个WPF应用程序,通过使用TiffBitmapEncoder将数百个BitMapSource转换为TIFF图像,从而节省了它们。然而,我有一个奇怪的内存消耗,它经常抛出内存不足异常

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+属性、构建选项卡、平台目标设置修复。