System.Drawing命名空间中哪些类会计入系统GDI对象总数?
理清System.Drawing中哪些对象计入系统GDI对象总数
你提到的这个问题确实是GDI资源管理里的高频疑惑——毕竟搞不清哪些对象占GDI计数,很容易踩资源泄漏的坑。我结合官方文档和实际测试经验给你梳理清楚:
哪些对象会计入系统GDI对象总数?
这些对象直接对应Windows原生GDI句柄,创建时会向系统申请GDI资源,必须手动释放(或通过using自动释放):
Pen:完全符合,它对应GDI的HPEN句柄,你创建1000个未释放的Pen,去任务管理器(详细信息列里勾选「GDI对象」)看进程的GDI计数,会明显增加1000左右,这也是你测试代码能验证的点Brush及其派生类(SolidBrush、LinearGradientBrush等):对应GDI的HBRUSH句柄Font:对应HFONT句柄,字体资源的占用很容易被忽略,尤其频繁创建Font又不释放的场景Bitmap:大部分场景下会计入,比如从本地文件加载、通过Graphics绘制生成的Bitmap,对应GDI的HBITMAP句柄;不过纯托管内存的Bitmap(比如通过Bitmap(int width, int height)创建的)可能不会,但保险起见还是要释放Region:对应HRGN句柄,用于区域裁剪时会占用GDI资源Graphics:它包装了GDI的HDC(设备上下文),虽然HDC的计数在任务管理器里可能单独体现,但本质上属于GDI资源范畴;注意从控件获取的Graphics(比如Control.CreateGraphics())不需要手动释放,但自己创建的(比如Graphics.FromImage())必须释放
哪些对象不会计入?
这些是纯托管对象,没有绑定原生GDI句柄,不会占用系统GDI计数:
Matrix:只是托管端的变换矩阵计算对象,完全在.NET托管内存中运行,和系统GDI资源无关GraphicsPath:它是托管端的路径描述容器,只有当你调用Graphics.DrawPath()这类渲染方法时,才会临时创建GDI资源用于绘制,但GraphicsPath本身不会计入GDI对象总数- 基础值类型(
Point、Size、Rectangle等):纯托管内存存储,和GDI资源完全不沾边
关键提醒:避免GDI泄漏
因为GDI对象是系统级资源,每个进程默认有GDI对象上限(通常是10000左右),超过后会出现绘制异常、程序崩溃等问题。所以一定要用using语句自动释放实现了IDisposable的GDI对象,比如:
using (var redPen = new Pen(Color.Red, 2)) using (var solidBrush = new SolidBrush(Color.Blue)) { // 执行绘制操作 g.DrawLine(redPen, 0, 0, 100, 100); g.FillRectangle(solidBrush, new Rectangle(50, 50, 200, 100)); }
这样代码块结束时,Pen和Brush会自动调用Dispose()释放对应的GDI句柄,不会造成泄漏。
内容的提问来源于stack exchange,提问作者glopes
相关产品推荐
相关产品推荐

