使用GDI+打印PNG24图像时出现GDI对象内存泄漏问题求助
I'm hitting a strange persistent GDI object leak on Windows 10 when printing to certain printers—even the Microsoft XPS Document Writer virtual printer exhibits this issue. The leak only seems to occur when working with PNG24 images (or more broadly, 32bppARGB bitmaps), and I've created test projects to reproduce the behavior consistently.
Reproduction Scenario 1: Using a PNG24 Image
This code loads a PNG24 file, copies it to an in-memory bitmap, then renders that bitmap to the printer's graphics context. After repeated prints, GDI object count spikes dramatically:
Imports System.Drawing Imports System.Drawing.Printing Module Module1 ' The PNG 24 source image Private Const SOURCE_PNG24_FILE As String = "[Path to any png 24 image]" ' The number of rendering repetitions Private Const REPETITIONS As Integer = 100 Sub Main() MsgBox("Open the task manager and check GDI objects count for this application, should be around 15.", MsgBoxStyle.Information) ' Get Microsoft XPS Document Writer printer settings Dim prnSettings As New PrinterSettings() With {.PrinterName = "Microsoft XPS Document Writer"} ' Ensure printer is valid If prnSettings.IsValid = False Then MsgBox("Can't find Microsoft XPS Document Writer.", MsgBoxStyle.Exclamation) Exit Sub End If ' Init document settings m_prtDoc = New PrintDocument With {.DocumentName = "PNG24 print test", .PrinterSettings = prnSettings} ' Start printing m_prtDoc.Print() MsgBox("Check GDI objects count, probably thru the roof.", MsgBoxStyle.Information) End Sub ' Document settings Private WithEvents m_prtDoc As PrintDocument = Nothing ' Page count Private m_iPageCount As Integer = 0 Private Sub PrintPage(sender As Object, e As PrintPageEventArgs) Handles m_prtDoc.PrintPage Try ' Load png 24 image Using imgSourcePng24 As Image = Image.FromFile(SOURCE_PNG24_FILE) ' Create in memory image of the same size Using imgMemory As New Bitmap(imgSourcePng24.Width, imgSourcePng24.Height) ' Get the in-memory graphics Using gphMemory As Graphics = Graphics.FromImage(imgMemory) ' Draw source image gphMemory.DrawImage(imgSourcePng24, New Rectangle(Point.Empty, imgSourcePng24.Size), New Rectangle(Point.Empty, imgSourcePng24.Size), GraphicsUnit.Pixel) End Using ' Draw in-memory image -> Comment this line and no GDI object spike e.Graphics.DrawImage(imgMemory, New Rectangle(Point.Empty, imgMemory.Size), New Rectangle(Point.Empty, imgMemory.Size), GraphicsUnit.Pixel) End Using End Using ' Increase page count m_iPageCount += 1 ' Print up to REPETITIONS pages e.HasMorePages = (m_iPageCount < REPETITIONS) Catch ex As Exception ' Error, Stop printing MsgBox(ex.Message, MsgBoxStyle.Critical) End Try End Sub End Module
Key Observations from Initial Testing
- The leak occurs on Windows 10 19042.867, but does NOT occur on Windows 7 with the same Microsoft XPS Document Writer.
- No leak happens when rendering PNG8 or JPG images, or when drawing the PNG24 directly to the printer's
Graphicsobject (skipping the in-memory bitmap step). - I've also seen this leak in a Win32 project, leading me to suspect it's related to the
GdipCreateBitmapFromScan0function called under the hood when creating empty bitmaps.
Reproduction Scenario 2: In-Memory 32bppARGB Bitmap
Further testing revealed the leak isn't limited to loaded PNGs—it happens whenever a 32bppARGB bitmap (with alpha channel content) is rendered to the printer's Graphics context:
Private Sub PrintPage(sender As Object, e As PrintPageEventArgs) Handles m_prtDoc.PrintPage Try ' Create in memory image Using imgMemory As New Bitmap(600, 400) ' Fill with alpha color Using gphMemory As Graphics = Graphics.FromImage(imgMemory) gphMemory.Clear(Color.FromArgb(128, 255, 0, 0)) ' Red at 0.5 alpha End Using ' Draw in-memory image e.Graphics.DrawImageUnscaled(imgMemory, e.PageBounds.Location) End Using ' Increase page counter m_iPageCount += 1 ' The number of rendering repetitions Const REPETITIONS As Integer = 20 ' Print up to REPETITIONS pages e.HasMorePages = (m_iPageCount < REPETITIONS) Catch ex As Exception ' Error, Stop printing MsgBox(ex.Message, MsgBoxStyle.Critical) End Try End Sub
I'm stuck on figuring out a workaround or root cause here—any help or insights would be greatly appreciated!
内容的提问来源于stack exchange,提问作者AndyDF

