我一直有困难理解System.Drawing
名称空间中的确切对象实际上对系统总GDI对象计数做出了贡献。例如,Matrix
对象是否计数?GraphicsPath
?Pen
?
为了测试这一点,在Form
初始化时运行了以下代码。
public partial class Form1 : Form
{
Timer timer = new Timer();
List<Pen> pens = new List<Pen>();
public Form1()
{
InitializeComponent();
var r = new Random();
for (int i = 0; i < 1000; i++)
{
var p = new Pen(
Color.FromArgb(r.Next(255), r.Next(255), r.Next(255)),
(float)r.NextDouble() * 10);
pens.Add(p);
}
timer.Interval = 30;
timer.Tick += timer_Tick;
timer.Start();
}
void timer_Tick(object sender, EventArgs e)
{
panel1.Invalidate();
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
for (int i = 0; i < pens.Count; i++)
{
e.Graphics.DrawLine(pens[i], (int)(20 + i * 0.1), 20, (int)(50 + i * 0.1), 50);
}
}
}
我惊讶地发现我的应用程序的GDI对象计数为32(使用任务管理器>详细信息> GDI对象列进行测量)。 即使我保留列表并强制Paint
事件使用每个生成的笔绘制单独的线条,情况也是如此。 我甚至尝试创建随机颜色以确保没有东西被重复使用,但GDI计数仍然稳定在32。
有很多帖子担心缓存和重用Pen
实例和其他对象,但我不确定是否所有System.Drawing
对象都会导致此计数。
也许现代GDI +实现实际上是懒惰的,并且只在您实际绘制某些内容时延迟分配?
当使用GDI +时,您无需像使用GDI时那样关注句柄和设备上下文。
似乎GDI +对GDI句柄进行了抽象处理,并尽可能避免使用它们。 这也与其他地方的报告一致,这些报告似乎表明GDI +仅在绝对需要时才会创建GDI句柄。 例如,只有在调用需要存在句柄的方法(例如GetHBitmap()
)时,Bitmap
才由句柄支持。
似乎,在现代GDI +中,Pen
、Brush
和许多其他System.Drawing
对象实际上并不会影响总的GDI对象计数。 当然,在C#中,如果它们没有被释放,它们仍会泄漏非托管内存,因为它们是由非托管GDI +对象支持的,但本机内存不像GDI内存那样严格。
如果当前解释未被争议,我将在接下来的几天内将其移到答案中。
Pen
句柄(33 个 GDI 对象总数)。我只是认为这是由于 GDI+ 的工作方式不同造成的。顺便说一下,我在 Windows 7 上进行测试。https://imgur.com/a/QC1CGOb - Bradley Uffner