Win32Exception“创建大量BitmapSource-Objects时,没有足够的存储空间来处理此命令”

时间:2015-12-04 10:04:49

标签: c# .net wpf

在我们的应用程序中,我们导出了大量图像,我们遇到了 Win32Exception

my-route

问题是,我们在不同的线程中创建了 BitmapSource 对象,并且存在内存泄漏。如果执行此代码,内存中仍有很多对象:

System.ComponentModel.Win32Exception (0x80004005): Not enough storage is available to process this command
    at MS.Win32.HwndWrapper..ctor(Int32 classStyle, Int32 style, Int32 exStyle, Int32 x, Int32 y, Int32 width, Int32 height, String name, IntPtr parent, HwndWrapperHook[] hooks)
    at System.Windows.Threading.Dispatcher..ctor()
    at System.Windows.DependencyObject..ctor()
    at System.Windows.Media.Imaging.BitmapSource..ctor(Boolean useVirtuals)
    at System.Windows.Media.Imaging.CachedBitmap..ctor(Int32 pixelWidth, Int32 pixelHeight, Double dpiX, Double dpiY, PixelFormat pixelFormat, BitmapPalette palette, Array pixels, Int32 stride)
    at System.Windows.Media.Imaging.BitmapSource.Create(Int32 pixelWidth, Int32 pixelHeight, Double dpiX, Double dpiY, PixelFormat pixelFormat, BitmapPalette palette, Array pixels, Int32 stride)

Screenshot of MemorySnapshot after Execution

我们在Windows服务中执行此操作,几天后系统崩溃。随着“没有足够的存储...” - 消息。此时很多其他应用程序崩溃,您无法打开编辑器或其他Windows应用程序。可能是桌面堆已满吗?内存不会增加(最大160MB),机器有16GB内存。

我们如何正确处理BitmapSource?

3 个答案:

答案 0 :(得分:0)

我们找到了一个解决方案,我们没有发现任何记忆泄漏:

List<Thread> threads = new List<Thread>();
for (int i = 0; i < 100; i++)
{
    Thread t = new Thread(new ThreadStart(() =>
    {
        BitmapSource temp = BitmapSource.Create(1, 1, 96, 96, PixelFormats.Bgr24, null, new byte[3], 3);

        // Shutdown Dispatcher
        if (temp.Dispatcher != null)
        {
            temp.Dispatcher.InvokeShutdown();
        }

        temp.Freeze();
    }));
    t.Start();
    threads.Add(t);
}
foreach (var thread in threads)
{
    thread.Join();
}
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();

我们必须看看这是否会导致其他问题,你怎么看?

答案 1 :(得分:0)

内存泄漏似乎与主线程上没有创建的位图以及保持引用的调度程序有关。您找到的解决方案可能有效。

但是,我想提出另一项改进建议。使用无限数量的线程可能不是一个好主意。使用线程池可能是有意义的。最简单的方法是使用Task.Run来安排线程池上的位图创建。事实上,在使用线程池时我没有看到任何内存泄漏。

var tasks = new List<Task>();
for (int i = 0; i < 100000; i++)
{
    var task = Task.Run(() =>
    {
        BitmapSource temp = null;
        temp = BitmapSource.Create(
            1,
            1,
            96,
            96,
            PixelFormats.Bgr24,
            null,
            new byte[3],
            3);
        temp.Freeze();
    });
    tasks.Add(task);
}

Task.WaitAll(tasks.ToArray());

答案 2 :(得分:-1)

正如您在.NET Reference Source中所看到的, BitmapSource.Create只需调用CachedBitmap构造函数,默认情况下使用BitmapCachinOptions.Default作为缓存选项。这意味着创建的每个位图都将保存在缓存中。

您需要使用从BitmapSoure继承的其他一些不使用缓存的类。如果您想自己创建位图,可以尝试WritableBitmap