Memory Leak in SolidBrush

G

Guest

I have tracked this down in reflector and SOS (Son of Strike) and know what
is going on but wanted an explanation. Copy this code into a windows forms
app and enable the timer with a Interval set to 10.

public partial class Form1 : Form
{
SolidBrush _brush;

public Form1()
{
InitializeComponent();
_brush = new SolidBrush(Color.Red);
}

private void timer1_Tick(object sender, EventArgs e)
{
_brush.Color = Color.Blue;
_brush.Color = SystemColors.Control;
}
}

I see lots of 16 byte WeakReference objects not being released. They are
being kept around by the static WeakReference array that is used inside of
the SolidBrush.Color property set (SystemColorTracker). What is the deal?

Brock
 
J

Jon Shemitz

breeve said:
I have tracked this down in reflector and SOS (Son of Strike) and know what
is going on but wanted an explanation.

I take it you understand that the point is to enable a brush set to a
system color to change automatically if the system color changes, but
you don't know how this is not leaking memory?
I see lots of 16 byte WeakReference objects not being released. They are
being kept around by the static WeakReference array that is used inside of
the SolidBrush.Color property set (SystemColorTracker). What is the deal?

The first if statement after the lock in SystemColorTracker.Add calls
GarbageCollectList if the list is full. GarbageCollectList, in turn,
calls CleanOutBrokenLinks, which packs the list: it finds all list
entries whose Target is null, and removes them from the list. A
WeakReference's Target is null when the object it pointed to has been
collected.

Iow, there's no leak. The list will retain dead weak references only
until list count equals list capacity.
 
J

Jeffrey Tan[MSFT]

Hi Brock,

I think your question is answered in "Jon Shemitz"'s reply. Have you
reviewed Jon's reply? Do you have anything unclear in this issue? Thanks.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

Guest

There is a memory leak here (run the code in Framework 2.0). We have seen it
in our code base (running GC.Collect doesn't help). It was reported by one of
our customers using our product. I ran SOS and you can plainly see the leak.
It consists of 16 byte WeakReference objects and lots of them. We have also
run DevPartner (Memory Analysis) and see the same leak. Just run the code and
you will see your memory climb over time.

Brock
 
J

Jon Shemitz

breeve said:
There is a memory leak here (run the code in Framework 2.0). We have seen it
in our code base (running GC.Collect doesn't help). It was reported by one of
our customers using our product. I ran SOS and you can plainly see the leak.
It consists of 16 byte WeakReference objects and lots of them. We have also
run DevPartner (Memory Analysis) and see the same leak. Just run the code and
you will see your memory climb over time.

A memory leak is memory that is never reclaimed; not memory that is
reclaimed slowly.

Connecting the dots in my previous message: When the SolidBrush is
collected, the WeakReference in the SystemColorTracker will go stale.
When you set 'enough' solid brushes to system colors, the
SystemColorTracker list will hit max capacity, and delete stale weak
references. That's two long cycles, and the interaction does mean that
the SystemColorTracker will hold weak references for a long time.

Even if you create your brushes within a `using` statement, so that
they get finalized as soon as you're done with them, they will stick
around until the next garbage collection. At that point, the weak
reference will go stale; next time the SystemColorTracker list fills
up, the weak reference will be delinked. Even then, the weak reference
will last until the next garbage collection; since the weak reference
has already survived a gen 0 collection, it will last until the next
gen 1 collection, while if the weak reference has already survived a
gen 1 collection, it will last until the next gen 2 collection. Gen 1
collections are rare, and gen 2 collections are even rarer. So, those
SystemColorTracker weak references will last for a long time - even
with SystemColorTracker at default capacity. If the SystemColorTracker
has had to increase its capacity, the whole cycle takes even longer.

Of course, if you don't create your brushes within a `using` statement
(or manually dispose of them), things take even longer than that! Now
the unreferenced brush hangs around, with a valid GDI+ handle, until
the next garbage collection. At that point, the gc treats it as live
data (promotes the brush to the next generation, and relocates it) and
adds it to the finalization queue. Now the brush won't get reclaimed
until the next (rare) gen 1 or gen 2 collection. When that finally
happens, the weak reference will go stale, and be delinked when the
SystemColorTracker next fills up. Of course, now the weak reference is
in gen 2, and so it will stick around for a very long time, too.

Bottom line: The behavior you and your customer are seeing is 100% in
line with what one would expect from the FCL code. Lots of very long
lived, very small objects.

Take away message: Using system colors with solid brushes has a
certain amount of overhead, in terms of small, long-lived objects.
Creating your solid brushes in a `using` statement will minimize this
overhead.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top