简体   繁体   English

System.Drawing 出 Memory 异常

[英]System.Drawing Out of Memory Exception

My application graphics engine throws these exceptions.我的应用程序图形引擎抛出这些异常。 They are all consumed by an empty catch block.它们都被一个空的 catch 块消耗掉。 In the early days I found one that was not trapped (associated with pen widening as I recall).在早期,我发现了一个没有被困住的(我记得与笔加宽有关)。 I surrounded it with try and an empty catch block.我用 try 和一个空的 catch 块包围它。 It seems that these exceptions have no effect on the drawing produced.这些异常似乎对生成的图纸没有影响。 I have done some reading on this without really understanding or getting to the bottom of it.我已经对此进行了一些阅读,但没有真正理解或深入了解它。

So to my questions:所以我的问题:

  1. Why would these be thrown if they can be consumed safely?如果可以安全食用,为什么还要扔掉它们? and
  2. Is it safe to ignore them?忽略它们是否安全? I worry that each one is having some hidden effect.我担心每一个都有一些隐藏的影响。 I have memory leaks which I have never found for example.例如,我有 memory 泄漏,我从未发现过。

I've seen System.Drawing throw OutOfMemoryExceptions even when it's not out of memory.我已经看到 System.Drawing 抛出 OutOfMemoryExceptions,即使它没有超出 memory。 Some GDI+ function is apparently just returning a stupid error code.一些 GDI+ function 显然只是返回一个愚蠢的错误代码。

IIRC, you will get an OutOfMemoryException if you try to use a LinearGradientBrush to fill a rectangle whose width or height is zero. IIRC,如果您尝试使用 LinearGradientBrush 填充宽度或高度为零的矩形,您将收到 OutOfMemoryException。 There may be other conditions too, but this is the main one we ran into.可能还有其他条件,但这是我们遇到的主要条件。

In that case, there's no need for a try/catch.在这种情况下,不需要 try/catch。 Just add an if statement to your drawing code, and don't fill the rectangle if the width or height is zero.只需将if语句添加到您的绘图代码中,如果宽度或高度为零,则不要填充矩形。

Update: According to the comments on this answer , it can also occur if you try to load a corrupted image file.更新:根据对此答案的评论,如果您尝试加载损坏的图像文件,也会发生这种情况。 For that, you would have no choice but to do try/catch.为此,您别无选择,只能尝试/捕获。

You're probably safe catching OutOfMemoryExceptions from GDI+, but keep the try blocks as small as possible.您可能可以安全地从 GDI+ 捕获 OutOfMemoryExceptions,但请尽量减小 try 块。 Consider logging the exceptions, so you can analyze the logs and add defensive code where possible.考虑记录异常,以便您可以分析日志并在可能的情况下添加防御性代码。 You don't want to mask a real OutOfMemoryException, but you don't want a stupid GDI+ error code to crash your app either.您不想掩盖真正的OutOfMemoryException,但也不希望愚蠢的 GDI+ 错误代码使您的应用程序崩溃。

It's a pretty bad exception: http://msdn.microsoft.com/en-us/library/system.outofmemoryexception.aspx .. not enough memory to continue execution of the program .这是一个非常糟糕的例外: http://msdn.microsoft.com/en-us/library/system.outofmemoryexception.aspx .. memory 不足以继续执行程序

You'll often find if you have so much allocated that 'simple' operations/allocations throw this message, the app will crash soon after.您经常会发现,如果您分配了这么多“简单”操作/分配会抛出此消息,应用程序很快就会崩溃。 If it's one massive allocation that's failing, you may be able to continue.如果这是一个失败的大规模分配,您也许可以继续。

If the app does anything important, you should try to close things down gracefully.如果应用程序做了任何重要的事情,您应该尝试优雅地关闭它们。

To explicitly answer your questions:要明确回答您的问题:

  1. They're thrown so the app has a chance to react/recover: some memory allocations (10GB worth of objects) might be expected to fail in many situations, perhaps a one-line app crash ( int[] x = new int[5368709120]; equivalent) should really throw an exception rather than crash everything它们被抛出,因此应用程序有机会做出反应/恢复:一些 memory 分配(价值 10GB 的对象)在许多情况下可能会失败,可能是单行应用程序崩溃( int[] x = new int[5368709120];等效) 应该真的抛出异常而不是使一切崩溃

  2. There should be no hidden effect, but if one allocation fails, then perhaps the next time you want a string or other useful object in some small way allocated for general operation of the app: things might become unstable.应该没有隐藏的影响,但如果一个分配失败,那么也许下次你想要一个string或其他有用的 object 以某种小方式分配给应用程序的一般操作:事情可能会变得不稳定。 That said depending on the environment, you might get this exception at any time..也就是说,根据环境,您可能随时会遇到此异常。

Edit: Anyone reading this should also consider that apparently GDI+ throws this exception for other reasons too.编辑:任何阅读本文的人也应该考虑到显然 GDI+ 也会出于其他原因抛出此异常。

I tried the solution 'Joe White' suggested and that was it.我尝试了“Joe White”建议的解决方案,就是这样。 It threw a OutOfMemoryException because the rectangle's width and height were 0. In my case the window was minimized when the exception occurred.它抛出了 OutOfMemoryException,因为矩形的宽度和高度为 0。在我的情况下,发生异常时 window 被最小化。

Here is an example;这是一个例子;

  Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)

    Using e
        ##Add conditions to avoid OutOfMemoryException##
        If (Not ClientRectangle.Width = 0) And (Not ClientRectangle.Height = 0) Then
            Using rect As GraphicsPath = New GraphicsPath()
                rect.AddRectangle(ClientRectangle)

                Using gb As New PathGradientBrush(rect)
                    gb.WrapMode = WrapMode.Tile
                    gb.SurroundColors = New Color() {GradientColors(1), GradientColors(0), GradientColors(2)}
                    gb.CenterColor = GradientColors(0)
                    gb.SetSigmaBellShape(0.5F)
                    e.Graphics.FillPath(gb, rect)
                End Using
            End Using
        End If
    End Using

End Sub

I had this line of code:我有这行代码:

bgpart = Primary.BackGround.Clone(rect, Primary.BackGround.PixelFormat);

That actually copies a part of the existing background.这实际上复制了现有背景的一部分。 The purpose was to copy the part of the background my starship was drawn on, so the starship can be moved and, each time, the proper background to be drawn.目的是复制绘制我的星舰的背景部分,以便可以移动星舰,并且每次都可以绘制正确的背景。 Simply put, 'something' moves on a standard background, and the background remains.简单地说,“某物”在标准背景上移动,而背景仍然存在。

Then this 'Out of memory' error of system.drawing start to manifest sometimes.然后这个 system.drawing 的“内存不足”错误有时会开始显现。 When i focus on it, i realize that it has nothing to do with use up all memory.当我专注于它时,我意识到它与用尽所有 memory 无关。 It should be called 'Out of memory RANGE', because what i found out is that on error cases, where i manage to emulate exactly, i asked him to read an image part that was actually outside the image itself , so the memory i ask him to read was not found into the memory of the object.它应该被称为“超出 memory 范围”,因为我发现在错误情况下,我设法准确地模拟,我让他读取实际上在图像本身之外的图像部分,所以我问的是 memory他读到object的memory没有发现。 Simply, the error raises when i moved the starship that was already out of the screen and into the screen, so ask him to copy a background non existent.简单地说,当我将已经离开屏幕的星际飞船移入屏幕时,错误就会出现,所以让他复制一个不存在的背景。

I replace my code with:我将我的代码替换为:

    Bitmap bgpart = null;
    try 
    {
        bgpart = Primary.BackGround.Clone(rect, Primary.BackGround.PixelFormat);
    } 
    catch(Exception e)
    {
        bgpart = Primary.BackGround.Clone(new Rectangle(0, 0, b.Width, b.Height), Primary.BackGround.PixelFormat);
    }

So actually i sent him to read a surely existing part, and problem solved.所以实际上我派他去阅读一个肯定存在的部分,问题就解决了。 In my case its ok because i try to read an non existent image part to draw it outside the screen - not needed anyways.就我而言,没关系,因为我尝试读取不存在的图像部分以将其绘制到屏幕外-无论如何都不需要。

So these errors are (also) thrown from system.drawing when it is forced to read memory not supposed to.因此,当 system.drawing 被迫读取不应该读取的 memory 时,这些错误(也)会从 system.drawing 中抛出。 If it is safe to bypass, that depends on usage of that readings.如果绕过是安全的,那取决于该读数的使用。

In my case it was safe because i was trying to read and write non existent image parts.就我而言,它是安全的,因为我试图读取和写入不存在的图像部分。

I'll tell you how I solved the problem.我会告诉你我是如何解决这个问题的。 Use windows os使用 windows 操作系统

  1. Open the Print & Scanner window.打开打印和扫描仪 window。

  2. Uncheck the box labeled Allow Windows to manage my default printer.取消选中标记为允许 Windows 管理我的默认打印机的框。

  3. Set the printer you want to use as the default printer.将要使用的打印机设置为默认打印机。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM