Microsoft Developer Network > Forenhomepage > .NET Base Class Library > GDI+ Problem with OutOfMemoryException rasied sometime from System.Drawing.Graphics.FromHdcInternal(IntPtr hdc)
Stellen Sie eine FrageStellen Sie eine Frage
 

BeantwortetGDI+ Problem with OutOfMemoryException rasied sometime from System.Drawing.Graphics.FromHdcInternal(IntPtr hdc)

  • Samstag, 30. August 2008 17:40Patrick SmacchiaMVPTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillen
     
    Hi,

    Me, and users of the .NET application I am working on, sometime get an OutOfmemoryException which callstack ends up with:

    Exception.Type {System.OutOfMemoryException}
    Exception.Message {Out of memory.}
    Exception.StackTrace {
    at System.Drawing.Graphics.FromHdcInternal(IntPtr hdc)


    I personally works with Windows Vista Ultimate x64, .NET 3.5 SP1, but it doesn't seems to comes from a particular version of the OS and of .NET since this problem sometime appears on x32 machines with .NET 2.0.

    Example of call stacks are:

    at System.Drawing.Graphics.FromHdcInternal(IntPtr hdc)
       at System.Drawing.Font.GetHeight()
       at System.Drawing.Font.get_Height()

    or
    at System.Drawing.Graphics.FromHdcInternal(IntPtr hdc)
       at System.Windows.Forms.PaintEventArgs.get_Graphics()
       at System.Windows.Forms.Control.PaintBackColor(PaintEventArgs e, Rectangle rectangle, Color backColor)
       at System.Windows.Forms.Control.PaintBackground(PaintEventArgs e, Rectangle rectangle, Color backColor, Point scrollOffset)
       at System.Windows.Forms.Control.PaintBackground(PaintEventArgs e, Rectangle rectangle)
       at System.Windows.Forms.Control.OnPaintBackground(PaintEventArgs pevent)
       at System.Windows.Forms.ScrollableControl.OnPaintBackground(PaintEventArgs e)
       at System.Windows.Forms.Control.PaintWithErrorHandling(PaintEventArgs e, Int16 layer, Boolean disposeEventArgs)
       at System.Windows.Forms.Control.WmEraseBkgnd(Message& m)
       at System.Windows.Forms.Control.WndProc(Message& m)
       at System.Windows.Forms.ScrollableControl.WndProc(Message& m)
       at System.Windows.Forms.ContainerControl.WndProc(Message& m)
       at System.Windows.Forms.SplitContainer.WndProc(Message& msg)
       at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)

    or

    at System.Drawing.Graphics.FromHdcInternal(IntPtr hdc)
       at System.Drawing.Font.ToLogFont(Object logFont)
       at System.Windows.Forms.RichTextBox.FontToLogFont(Font value, LOGFONT logfont)
       at System.Windows.Forms.RichTextBox.SetCharFormatFont(Boolean selectionOnly, Font value)
       at System.Windows.Forms.RichTextBox.set_SelectionFont(Font value)

    Reflector tells me that it is the win32 methods GdipCreateFromHDC() from gdiplus.dll that returns a status equals to 3.

    The problem happens rarely, but often enough to bothers some our users.
    Could it be a lack of Dispose() on some handles on GDI+ objects?

    Any help would be highly appreciated.
    Thanks,

    Patrick Smacchia
    MVP Visual C#
    Lead Developer of NDepend     http://www.NDepend.com
    Author of:    Practical .NET2 and C#2  http://www.practicaldot.net

    Patrick (at) Smacchia (dot) com

Antworten

  • Montag, 1. September 2008 14:09nobugzMVP, ModeratorTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillen
     Beantwortet
    GDI+ generates pretty lousy exceptions, you can get OOM in error conditions that have nothing whatsoever to do with running out of memory.  With this call stack, I'd say you are probably running out of GDI handles.  There's a limit of 10,000 handles for a process.  Not calling Dispose() on graphics objects is indeed a good way to trip the problem.  You would have to get into a condition where you do lots of painting but not allocate sufficient managed objects to trip a garbage collection.  That's very hard to do.  Perhaps the real leak is elsewhere, CopyFromScreen() in .NET 2.0 SP1 had a handle leak for example.
    Hans Passant.

Alle Antworten

  • Samstag, 30. August 2008 18:30JohnWein TeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillen
     
    I don't think .NET GDI+ is quite ready for prime time.  If you're doing something other than normal control painting, consider calling the GDI API methods directly.
    • BearbeitetJohnWein Samstag, 30. August 2008 18:31added .NET
    •  
  • Montag, 1. September 2008 07:30Patrick SmacchiaMVPTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillen
     
    John, so far our application is massively using GDI+ with just one case where this OutOfMemoryException was raised. It seems that only recently the number of occurences of the problem increase.
    Patrick (at) Smacchia (dot) com
  • Montag, 1. September 2008 14:09nobugzMVP, ModeratorTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillen
     Beantwortet
    GDI+ generates pretty lousy exceptions, you can get OOM in error conditions that have nothing whatsoever to do with running out of memory.  With this call stack, I'd say you are probably running out of GDI handles.  There's a limit of 10,000 handles for a process.  Not calling Dispose() on graphics objects is indeed a good way to trip the problem.  You would have to get into a condition where you do lots of painting but not allocate sufficient managed objects to trip a garbage collection.  That's very hard to do.  Perhaps the real leak is elsewhere, CopyFromScreen() in .NET 2.0 SP1 had a handle leak for example.
    Hans Passant.
  • Montag, 1. September 2008 14:15Patrick SmacchiaMVPTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillenTeilnehmermedaillen
     
    Hans, I think you are right, my process is certainly running out of GDI handles. Meantime, I found this following thread where several programmers have the same problem and an MSFT ends up to the conclusion that some GDI object are not properly disposed before they are collected.
    http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=161567&SiteID=1 
    Patrick (at) Smacchia (dot) com