C# GDI+ System.Drawing.Bitmap 给出错误参数间歇性无效
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/130790/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
GDI+ System.Drawing.Bitmap gives error Parameter is not valid intermittently
提问by
I have some C# code in an ASP.Net application that does this:
我在执行此操作的 ASP.Net 应用程序中有一些 C# 代码:
Bitmap bmp = new Bitmap(1184, 1900);
位图 bmp = 新位图 (1184, 1900);
And occasionally it throws an exception "Parameter is not valid". Now i've been googling around and apparently GDI+ is infamous for throwing random exceptions, and lots of people have had this problem, but nobody has a solution to it! I've checked the system and it has plenty of both RAM and swap space. Now in the past if i do an 'iisreset' then the problem goes away, but it comes back in a few days. But i'm not convinced i've caused a memory leak, because as i say above there is plenty of ram+swap free.
有时它会抛出异常“参数无效”。现在我一直在谷歌搜索,显然 GDI+ 因抛出随机异常而臭名昭著,很多人都遇到过这个问题,但没有人有解决方案!我检查了系统,它有足够的 RAM 和交换空间。现在过去,如果我执行“iisreset”,问题就会消失,但几天后又会出现。但我不相信我造成了内存泄漏,因为正如我上面所说的,有很多 ram+swap 免费。
Anyone have any solutions?
任何人都有任何解决方案?
回答by Lou Franco
You not only need enough memory, it needs to be contiguous. Over time memory becomes fragmented and it becomes harder to find big blocks. There aren't a lot of good solutions to this, aside from building up images from smaller bitmaps.
您不仅需要足够的内存,还需要连续。随着时间的推移,内存变得碎片化,并且很难找到大块。除了从较小的位图构建图像之外,没有很多好的解决方案。
new Bitmap(x, y) pretty much just needs to allocate memory -- assuming that your program isn't corrupted in some way (is there any unsafe code that could corrupt the heap), then I would start with this allocation failing. Needing a contiguous block is how a seemingly small allocation could fail. Fragmentation of the heap is something that is usually solved with a custom allocator -- I don't think this is a good idea in IIS (or possible).
new Bitmap(x, y) 几乎只需要分配内存——假设你的程序没有以某种方式损坏(是否有任何可能损坏堆的不安全代码),那么我将从这个分配失败开始。需要一个连续的块是看似很小的分配可能会失败的原因。堆的碎片通常是用自定义分配器解决的——我认为这在 IIS 中不是一个好主意(或可能)。
To see what error you get on out of memory, try just allocation a gigantic Bitmap as a test -- see what error it throws.
要查看内存不足会出现什么错误,请尝试分配一个巨大的 Bitmap 作为测试——看看它会抛出什么错误。
One strategy I've seen is to pre-allocate some large blocks of memory (in your case Bitmaps) and treat them as a pool (get and return them to the pool). If you only need them for a short period of time, you might be able to get away with just keeping a few in memory and sharing them.
我见过的一种策略是预先分配一些大内存块(在您的情况下是位图)并将它们视为一个池(获取并将它们返回到池中)。如果您只在短时间内需要它们,您可能只需在内存中保留一些并共享它们即可。
回答by Lou Franco
I just got a reply from microsoft support. Apparently if you look here:
我刚收到微软支持的回复。显然,如果你看这里:
http://msdn.microsoft.com/en-us/library/system.drawing.aspx
http://msdn.microsoft.com/en-us/library/system.drawing.aspx
You can see it says "Classes within the System.Drawing namespace are not supported for use within a Windows or ASP.NET service. Attempting to use these classes from within one of these application types may produce unexpected problems, such as diminished service performance and run-time exceptions." So they're basically washing their hands of the issue. It appears that they're admitting that this section of the .Net framework is unreliable. I'm a bit disappointed.
您可以看到它说“不支持在 Windows 或 ASP.NET 服务中使用 System.Drawing 命名空间中的类。尝试从这些应用程序类型之一中使用这些类可能会产生意外问题,例如服务性能下降和运行时异常。” 所以他们基本上是在解决这个问题。他们似乎承认 .Net 框架的这一部分不可靠。我有点失望。
Next up - can anyone recommend a similar library to open a gif file, superimpose some text, and save it again?
接下来 - 谁能推荐一个类似的库来打开一个 gif 文件,叠加一些文本,然后再次保存?
回答by Jason Kealey
Everything I've seen to date in my context is related to memory leaks / handle leaks. I recommend you get a fresh pair of eyes to investigate your code.
迄今为止,我在上下文中看到的所有内容都与内存泄漏/句柄泄漏有关。我建议你重新审视你的代码。
What actually happens is that the image is disposed at a random point in the future, even if you've created it on the previous line of code. This may be because of a memory/handle leak (cleaning some out of my code appears to improve but not completely resolve this problem).
实际发生的情况是,即使您在前一行代码中创建了该图像,该图像也将在未来的某个随机点上进行处理。这可能是因为内存/句柄泄漏(从我的代码中清除一些似乎有所改善,但并未完全解决此问题)。
Because this error happens after the application has been in use for a while, sometimes using lots of memory, sometimes not, I feel the garbage collector doesn't obey the rules because of some special tweaks related to services and that is why Microsoft washes their hands of this problem.
因为这个错误发生在应用程序使用一段时间后,有时使用大量内存,有时没有,我觉得垃圾收集器不遵守规则,因为一些与服务相关的特殊调整,这就是为什么微软清洗他们的手上有这个问题。
http://blog.lavablast.com/post/2007/11/The-Mysterious-Parameter-Is-Not-Valid-Exception.aspx
http://blog.lavablast.com/post/2007/11/The-Mysterious-Parameter-Is-Not-Valid-Exception.aspx
回答by Frank Krueger
Stop using GDI+ and start using the WPF Imaging classes (.NET 3.0). These are a major cleanup of the GDI+ classes and tuned for performance. Additionally, it sets up a "bitmap chain" that allows you to easily perform multiple actions on the bitmap in an efficient manner.
停止使用 GDI+ 并开始使用 WPF 成像类 (.NET 3.0)。这些是 GDI+ 类的主要清理,并针对性能进行了调整。此外,它还设置了一个“位图链”,允许您以有效的方式轻松地对位图执行多项操作。
Find more by reading about BitmapSource
通过阅读BitmapSource了解更多信息
Here's an example of starting with a blank bitmap just waiting to receive some pixels:
这是一个从空白位图开始等待接收一些像素的示例:
using System.Windows.Media.Imaging;
class Program {
public static void Main(string[] args) {
var bmp = new WriteableBitmap(1184, 1900, 96.0, 96.0, PixelFormat.Bgr32, null);
}
}
回答by Frank Krueger
For anyone who's interested, the solution i'm going to use is the Mono.Cairo libraries from the mono C# distribution instead of using system.drawing. If i simply drag the mono.cairo.dll, libcairo-2.dll, libpng13.dll and zlib1.dll files from the windows version of mono into the same folder as my executable, then i can develop in windows using visual studio 2005 and it all works nicely.
对于任何感兴趣的人,我将使用的解决方案是来自单声道 C# 发行版的 Mono.Cairo 库,而不是使用 system.drawing。如果我只是将 mono.cairo.dll、libcairo-2.dll、libpng13.dll 和 zlib1.dll 文件从 Windows 版本的 Mono 拖到与我的可执行文件相同的文件夹中,那么我可以使用 Visual Studio 2005 在 Windows 中进行开发和这一切都很好。
Update - i've done the above, and stress tested the application and it all seems to run smoothly now, and uses up to 200mb less ram to boot. Very happy.
更新 - 我已经完成了上述操作,并对应用程序进行了压力测试,现在一切似乎都运行顺利,并且使用最多 200 mb 的内存来启动。很高兴。
回答by Tony Edgecombe
Classes within the System.Drawing namespace are not supported for use within a Windows or ASP.NET service
System.Drawing 命名空间中的类不支持在 Windows 或 ASP.NET 服务中使用
For a supported alternative, see Windows Imaging Components(msdn), a native library which ironically System.Drawing is based on.
有关受支持的替代方案,请参阅Windows Imaging Components( msdn),具有讽刺意味的是 System.Drawing 所基于的本机库。