Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.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
C# Win32Exception“;存储空间不足,无法处理此命令;创建大量BitmapSource对象时_C#_.net_Wpf - Fatal编程技术网

C# Win32Exception“;存储空间不足,无法处理此命令;创建大量BitmapSource对象时

C# Win32Exception“;存储空间不足,无法处理此命令;创建大量BitmapSource对象时,c#,.net,wpf,C#,.net,Wpf,在我们的应用程序中,我们导出了大量图像,并遇到了此Win32Exception: 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, Int3

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

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)
问题是,我们在不同的线程中创建BitmapSource对象,并且存在内存泄漏。如果执行此代码,内存中仍有许多对象:

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);
        temp.Freeze();
    }));
    t.Start();
    threads.Add(t);
}
foreach (var thread in threads)
{
    thread.Join();
}
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
List threads=newlist();
对于(int i=0;i<100;i++)
{
线程t=新线程(新线程开始(()=>
{
BitmapSource temp=BitmapSource.Create(1,1,96,96,PixelFormats.Bgr24,null,新字节[3],3);
温度冻结();
}));
t、 Start();
添加(t);
}
foreach(线程中的var线程)
{
thread.Join();
}
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();

我们在Windows服务中执行此操作,几天后系统崩溃。带有“存储空间不足…”消息。此时,许多其他应用程序崩溃,您无法打开编辑器或其他Windows应用程序。桌面堆是否已满?内存不会增加很多(最大160MB),而且机器有16GB的RAM

如何正确处理位图源?如中所示,
BitmapSource.Create
只需调用
CachedBitmap
构造函数,默认情况下,该构造函数使用
BitmapCachinOptions.default
作为缓存选项。这意味着创建的每个位图都将保存在缓存中

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

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


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

我们找到了一个解决方案,没有发现内存泄漏:

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();
List threads=newlist();
对于(int i=0;i<100;i++)
{
线程t=新线程(新线程开始(()=>
{
BitmapSource temp=BitmapSource.Create(1,1,96,96,PixelFormats.Bgr24,null,新字节[3],3);
//停机调度员
如果(临时调度器!=null)
{
temp.Dispatcher.InvokeShutdown();
}
温度冻结();
}));
t、 Start();
添加(t);
}
foreach(线程中的var线程)
{
thread.Join();
}
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();

我们必须看看这是否会导致其他问题,您认为如何?

我们找到了一个解决方案,我们没有发现memroy泄漏:

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();
List threads=newlist();
对于(int i=0;i<100;i++)
{
线程t=新线程(新线程开始(()=>
{
BitmapSource temp=BitmapSource.Create(1,1,96,96,PixelFormats.Bgr24,null,新字节[3],3);
//停机调度员
如果(临时调度器!=null)
{
temp.Dispatcher.InvokeShutdown();
}
温度冻结();
}));
t、 Start();
添加(t);
}
foreach(线程中的var线程)
{
thread.Join();
}
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();

我们必须看看这是否会导致其他问题,您认为如何?

内存泄漏似乎与未在主线程上创建位图以及dispatcher保留引用有关。您找到的解决方案可能有效

然而,我想建议另一个改进。使用无限数量的线程可能不是一个好主意。使用线程池可能是有意义的。最简单的方法是使用
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());
var tasks=newlist();
对于(int i=0;i<100000;i++)
{
var task=task.Run(()=>
{
BitmapSource temp=null;
temp=BitmapSource.Create(
1.
1.
96,
96,
PixelFormats.Bgr24,
无效的
新字节[3],
3);
温度冻结();
});
任务。添加(任务);
}
Task.WaitAll(tasks.ToArray());

内存泄漏似乎与未在主线程上创建位图以及dispatcher保留引用有关。您找到的解决方案可能有效

然而,我想建议另一个改进。使用无限数量的线程可能不是一个好主意。使用线程池可能是有意义的。最简单的方法是使用
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());
var tasks=newlist();
对于(int i=0;i<100000;i++)
{
var task=task.Run(()=>
{
BitmapSource temp=null;
temp=BitmapSource.Create(
1.
1.
96,
96,
PixelFormats.Bgr24,
无效的
新字节[3],
3);
温度冻结();
});
任务。添加(任务);
}
Task.WaitAll(tasks.ToArray());

是否在某处保留对
BitmapSource
对象的引用?一旦不再使用BitmapSource,GC应该进行清理,根据Nope的说法,这是导致内存和可能的句柄泄漏的整个代码片段,我现在看到了问题所在。仅当BitmapSource在其自己的线程上创建时,才会发生此错误。可能是错误/不受支持的情况(看起来调度器可能保留了一个防止垃圾收集的引用)您是否保留了对
BitmapSource
对象的引用?一旦不再使用BitmapSource,GC就应该进行清理,根据Nope的说法,这是lea的全部代码片段