为什么System.Drawing.dll中存在C#OutOfMemory异常?
让我们简化模型为什么System.Drawing.dll中存在C#OutOfMemory异常?,c#,.net,winforms,C#,.net,Winforms,让我们简化模型 class Container { //other members public byte[] PNG; } class Producer { public byte[] Produce(byte[] ImageOutside) { using (MemoryStream bmpStream = new MemoryStream(ImageOutside), pngStream = new MemoryS
class Container
{
//other members
public byte[] PNG;
}
class Producer
{
public byte[] Produce(byte[] ImageOutside)
{
using (MemoryStream bmpStream = new MemoryStream(ImageOutside),
pngStream = new MemoryStream())
{
System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(bmpStream);
bitmap.Save(pngStream, System.Drawing.Imaging.ImageFormat.Png);
pngStream.Seek(0, System.IO.SeekOrigin.Begin);
byte[] PNG = new byte[pngStream.Length];
pngStream.Read(PNG, 0, (int)pngStream.Length);
bitmap.Dispose();
GC.Collect();
GC.WaitForPendingFinalizers();
return PNG;
}
}
}
主函数保持makeContainer=newcontainer()
为container.PNG和Queue.Enqueue(container)
use using()子句根本不起作用
虽然这个过程重复了大约40多次(不同),但它抛出了一个异常。有时是OutOfMemoryException,有时是“GDI+正常错误”(我不确定它在英语中的确切含义,我只是翻译了一下)。
但是,如果我尝试捕捉异常并简单地忽略它,它仍然可以继续产生更多,但不是无限的,只是更向前。
当抛出第一个异常时,任务管理器中显示的占用内存仅为600-700 MB,最终在1.2GB左右停止。我试过这个:
while (true)
{
Bitmap b = new Bitmap(4500, 5000);
list.Add(b);
Invoke((MethodInvoker)delegate { textBox1.Text = list.Count.ToString(); });
}
虽然99%的内存(约11GB)已分配给该程序,但它从未引发任何异常,所发生的只是textBox1中的数字不再上升
避免这种情况的方法可能不是生产这么多东西,但我仍然想知道内部原理和原因,并感谢您的帮助。with
byte[]PNG=new byte[pngStream.Length]代码>分配大量内存来存储图像
后续调用无效,您已处理该流
GC.Collect();
GC.WaitForPendingFinalizers();
无法释放PNG数组使用的内存,因为函数return中有活动引用
我建议返回一个流,而不是一个字节数组
否则,在调用方法product
后,记得在再次调用之前删除对PNG的引用
样本:
while (true)
{
Byte[] b = new Byte[1000];
b = this.Produce(b);
//Use your array as you need, but you can't assign it to external property, otherwise memory cannot be released
b = null; //remove the reference, (in reality, in this example assign null is not necessary, because b will be overwritten at next loop.
GC.Collect(); //Force garbage collector, probably not necessarry, but can be useful
GC.WaitForPendingFinalizers();
}
平台编译可能会影响最大可用内存:
- 在32位应用程序中,可用内存最多为2 GiB
- 在64位应用程序中,您有2个Tib的可用内存,但
单个对象(类)不能超过2 Gib
- 在UWP应用程序中,依赖于
装置
- 当你启动应用程序时,任何CPU都会被及时编译,
并且可以运行32位和64位,这取决于机器架构
和系统配置
带有
字节[]PNG=新字节[pngStream.Length]代码>分配大量内存来存储图像
后续调用无效,您已处理该流
GC.Collect();
GC.WaitForPendingFinalizers();
无法释放PNG数组使用的内存,因为函数return中有活动引用
我建议返回一个流,而不是一个字节数组
否则,在调用方法product
后,记得在再次调用之前删除对PNG的引用
样本:
while (true)
{
Byte[] b = new Byte[1000];
b = this.Produce(b);
//Use your array as you need, but you can't assign it to external property, otherwise memory cannot be released
b = null; //remove the reference, (in reality, in this example assign null is not necessary, because b will be overwritten at next loop.
GC.Collect(); //Force garbage collector, probably not necessarry, but can be useful
GC.WaitForPendingFinalizers();
}
平台编译可能会影响最大可用内存:
- 在32位应用程序中,可用内存最多为2 GiB
- 在64位应用程序中,您有2个Tib的可用内存,但
单个对象(类)不能超过2 Gib
- 在UWP应用程序中,依赖于
装置
- 当你启动应用程序时,任何CPU都会被及时编译,
并且可以运行32位和64位,这取决于机器架构
和系统配置
您需要处理创建的每个位图。你可能已经用完了图形句柄。While(true)是一个无限循环,它将以最快的速度运行,直到你中断为止。而空的使用带有空文件夹的也没有任何作用。不幸的是,系统.Drawing
类有一个坏习惯,即有效地执行“是特定的坏情况a吗?我将抛出此异常。是特定的坏情况b吗?我将抛出该异常。对于任何其他错误情况,我将猜测它是OutOfMemory”-也就是说,当基本问题与内存无关时,它通常会引发此异常。@Hans Passant我不明白,因为我需要的只是字节[],我已经在处理流之前处理了位图。为什么流必须保持可读性?什么是潜在的蒸汽?没有下划线。您一直在列表中添加大型位图;这很可能不是关于内存,而是关于“GDI句柄”。在任务管理器中观察它们不断上升,直到您的任务结束。您需要处理创建的每个位图。你可能已经用完了图形句柄。While(true)是一个无限循环,它将以最快的速度运行,直到你中断为止。而空的使用带有空文件夹的也没有任何作用。不幸的是,系统.Drawing
类有一个坏习惯,即有效地执行“是特定的坏情况a吗?我将抛出此异常。是特定的坏情况b吗?我将抛出该异常。对于任何其他错误情况,我将猜测它是OutOfMemory”-也就是说,当基本问题与内存无关时,它通常会引发此异常。@Hans Passant我不明白,因为我需要的只是字节[],我已经在处理流之前处理了位图。为什么流必须保持可读性?什么是潜在的蒸汽?没有下划线。您一直在列表中添加大型位图;这很可能不是关于内存,而是关于“GDI句柄”。在任务管理器中观察它们不断上升,直到您的任务完成。。