I have been having difficulties understanding which exact objects from the System.Drawing
namespace actually contribute to the system total GDI object count. For instance, do Matrix
objects count? GraphicsPath
? Pen
?
In order to test this, I ran the following code on Form
initialization.
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);
}
}
}
I was surprised to find that my application GDI object count was 32 (measured with Task Manager > Details > GDI objects column). This was true even if I kept the list around and forced the Paint
event to draw individual lines with each of the generated pens. I even tried creating random colors to ensure that nothing got reused and still the GDI count kept steady at 32.
There are a lot of posts worrying about caching and reusing Pen
instances and other objects, but it is not clear to me whether all System.Drawing
objects contribute to this count.
Maybe modern GDI+ implementations are actually lazy and delay allocation only to when you are actually drawing something?
Update: GSerg pointed out that the MSDN official documentation says
When you use GDI+, you don't have to be as concerned with handles and device contexts as you do when you use GDI.
It seems that GDI+ abstracts over GDI handle and avoids using them as much as possible. This is also consistent with reports elsewhere that seem to indicate that GDI+ only actually creates a GDI handle when it absolutely has to. For example, a Bitmap
is only backed by a handle if you call methods that require a handle to exist, e.g. GetHBitmap()
.
It seems that, at least in modern GDI+, Pen
, Brush
and many other System.Drawing
objects do not actually contribute to the total GDI object count. Of course, in C# they still leak unmanaged memory if they are not disposed, since they are backed by unmanaged GDI+ objects, but native memory is not such a harsh mistress as GDI memory.
If this current interpretation is not contested, I will move it to an answer over the next few days.
GDI Objects (Graphics Device Interface) is a core windows component responsible for representing graphical objects and outputting them to devices such as printers or monitors. For every window or application that is open, it uses up GDI Objects.
Here's a list of the GDI derived classes: CBitmap—A bitmap is an array of bits in which one or more bits correspond to each display pixel. You can use bitmaps to represent images, and you can use them to create brushes. CBrush—A brush defines a bitmapped pattern of pixels that is used to fill areas with color.
What are GDI Handles? GDI stands for Graphical Device Interface and every process that displays graphical objects and formatted text uses it. By default, each process has a limit of 10 000 GDI handles. Just like when CPU usage is high or available RAM is low, your computer can become unstable, when GDI handles run low.
The following objects cause a GDI handle to be created:
This list was drawn up by using the information from here: https://learn.microsoft.com/en-gb/windows/desktop/SysInfo/gdi-objects
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With