The StatusStrip control leaks when you clear its Items collection. You
can try the code below. Yes, this looks like an odd way to use a
progress bar but I distilled this snippet from a moderately large
application that was running out of user handles (10000 max) after
some hours of use because of just this problem. Try it. Just make a
form with a timer, a button, a label, and a StatusStrip. Push the
button and you will see it leak user handles in the task manager.

Workaround: Explicitly dispose each toolstrip item before clearing the
collection. Set DONT_LEAK = True to do this.

Is there a better way to solve the problem? Please tell me.

I found a few articles on MSDN about leaks with StatusStrips but none
of them appear related to this. In particular I have AllowItemReorder
= False, so this is not the problem that was reported to occur when
you have that set True.

Thanks for listening,
Carl

Public Class Form1
Private Const DONT_LEAK As Boolean = False
Private progressCount As Integer
Private progressTarget As Integer = 20000
Private Sub cmdThrashStrip_Click(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles cmdThrashStrip.Click
progressCount = 0
Timer1.Interval = 10
Timer1.Enabled = True
End Sub
Private Sub UpdateProgress()
Try
If DONT_LEAK Then
' Disposing directly from collections gives
"collection modified" exception
' from enumerator
Dim killList As New Generic.List(Of ToolStripItem)
For Each item As ToolStripItem In StatusStrip1.Items
killList.Add(item)
Next
StatusStrip1.Items.Clear()
For Each item As ToolStripItem In killList
item.Dispose()
Next
Else
StatusStrip1.Items.Clear()
End If
Dim pb As New ToolStripProgressBar
pb.Value = 100 * progressCount / progressTarget
StatusStrip1.Items.Add(pb)
If progressCount >= progressTarget Then
Timer1.Enabled = False
StatusStrip1.Items.Add("Done")
End If
Catch ex As Exception
' Ha! No handle left to even put up a message box!
Label1.Text = ex.Message
End Try
End Sub
Private Sub Timer1_Tick(ByVal sender As Object, ByVal e As
System.EventArgs) Handles Timer1.Tick
progressCount += 1
UpdateProgress()
End Sub
End Class

Re: StatusStrip control leaks its collection items by carl

carl
Thu Jul 10 12:49:24 CDT 2008

I didn't mention the other workaround: instead of adding a new
progress bar, search the collection and re-use the existing one. This
works fine in my little example. However my bigger application still
leaks when I do this, although at a much lower rate. I'll revisit that
in light of my experience with the little snippet.

-- Carl

RE: StatusStrip control leaks its collection items by FamilyTreeMike

FamilyTreeMike
Thu Jul 10 14:52:00 CDT 2008

It would seem to make sense that you would have issues if you don't dispose
something that can be disposed.

Why don't you just make a single instance visible or not visible? What I do
is allocate all the controls on the status strip in the designer and use them
in place as needed.

"carl.clawson@pkinetics.com" wrote:

> The StatusStrip control leaks when you clear its Items collection. You
> can try the code below. Yes, this looks like an odd way to use a
> progress bar but I distilled this snippet from a moderately large
> application that was running out of user handles (10000 max) after
> some hours of use because of just this problem. Try it. Just make a
> form with a timer, a button, a label, and a StatusStrip. Push the
> button and you will see it leak user handles in the task manager.
>
> Workaround: Explicitly dispose each toolstrip item before clearing the
> collection. Set DONT_LEAK = True to do this.
>
> Is there a better way to solve the problem? Please tell me.
>
> I found a few articles on MSDN about leaks with StatusStrips but none
> of them appear related to this. In particular I have AllowItemReorder
> = False, so this is not the problem that was reported to occur when
> you have that set True.
>
> Thanks for listening,
> Carl
>
> Public Class Form1
> Private Const DONT_LEAK As Boolean = False
> Private progressCount As Integer
> Private progressTarget As Integer = 20000
> Private Sub cmdThrashStrip_Click(ByVal sender As System.Object,
> ByVal e As System.EventArgs) Handles cmdThrashStrip.Click
> progressCount = 0
> Timer1.Interval = 10
> Timer1.Enabled = True
> End Sub
> Private Sub UpdateProgress()
> Try
> If DONT_LEAK Then
> ' Disposing directly from collections gives
> "collection modified" exception
> ' from enumerator
> Dim killList As New Generic.List(Of ToolStripItem)
> For Each item As ToolStripItem In StatusStrip1.Items
> killList.Add(item)
> Next
> StatusStrip1.Items.Clear()
> For Each item As ToolStripItem In killList
> item.Dispose()
> Next
> Else
> StatusStrip1.Items.Clear()
> End If
> Dim pb As New ToolStripProgressBar
> pb.Value = 100 * progressCount / progressTarget
> StatusStrip1.Items.Add(pb)
> If progressCount >= progressTarget Then
> Timer1.Enabled = False
> StatusStrip1.Items.Add("Done")
> End If
> Catch ex As Exception
> ' Ha! No handle left to even put up a message box!
> Label1.Text = ex.Message
> End Try
> End Sub
> Private Sub Timer1_Tick(ByVal sender As Object, ByVal e As
> System.EventArgs) Handles Timer1.Tick
> progressCount += 1
> UpdateProgress()
> End Sub
> End Class
>

Re: StatusStrip control leaks its collection items by carl

carl
Thu Jul 10 15:55:31 CDT 2008

On Jul 10, 12:52=A0pm, Family Tree Mike
<FamilyTreeM...@discussions.microsoft.com> wrote:
> It would seem to make sense that you would have issues if you don't dispo=
se
> something that can be disposed.

I don't expect to have to dispose things explicitly unless there's a
reason that I need to have it done at a specific point in the code.
That's what the garbage collector is for. In the case of the Status
Strip, removed controls are not getting garbage collected. Any other
control collection I've ever used will release its contents properly
on a Clear( ) or Remove( ), and they then become eligible for garbage
collection if no other references to them exist.

If there's something special about the StatusStrip that I'm not
getting, someone please clue me in. I don't see in its documentation
that any special handling is required for it or its Items collection.

> Why don't you just make a single instance visible or not visible? =A0What=
I do
> is allocate all the controls on the status strip in the designer and use =
them
> in place as needed.

Good idea. My example wasn't meant to demonstrate how one SHOULD do
it. It was to demonstrate a problem. The code was silly but it
shouldn't have leaked 10,000 handles all over the floor.

-- Carl

Re: StatusStrip control leaks its collection items by Jack

Jack
Thu Jul 10 18:54:02 CDT 2008

On Thu, 10 Jul 2008 13:55:31 -0700 (PDT), carl.clawson@pkinetics.com
wrote:

>On Jul 10, 12:52 pm, Family Tree Mike
><FamilyTreeM...@discussions.microsoft.com> wrote:
>> It would seem to make sense that you would have issues if you don't dispose
>> something that can be disposed.
>
>I don't expect to have to dispose things explicitly unless there's a
>reason that I need to have it done at a specific point in the code.
>That's what the garbage collector is for. In the case of the Status
>Strip, removed controls are not getting garbage collected. Any other
>control collection I've ever used will release its contents properly
>on a Clear( ) or Remove( ), and they then become eligible for garbage
>collection if no other references to them exist.
>
>If there's something special about the StatusStrip that I'm not
>getting, someone please clue me in. I don't see in its documentation
>that any special handling is required for it or its Items collection.
>
>> Why don't you just make a single instance visible or not visible?  What I do
>> is allocate all the controls on the status strip in the designer and use them
>> in place as needed.
>
>Good idea. My example wasn't meant to demonstrate how one SHOULD do
>it. It was to demonstrate a problem. The code was silly but it
>shouldn't have leaked 10,000 handles all over the floor.
>
>-- Carl

There are several interrelated things going on here.

The StatusStrip controls won't be eligible for garbage collection
until all references to them are gone.

The Windows resources held by those controls will be freed either when
you Dispose them or when the garbage collector frees them.

The garbage collector knows nothing about non-managed resources like
Windows handles. Even if all references to the controls are gone, the
garbage collector won't run until the app needs more memory and that
might not occur before your app runs out of handles.

You should always Dispose any object that uses non-managed resources
when you are finished with it.

Re: StatusStrip control leaks its collection items by Peter

Peter
Thu Jul 10 20:00:53 CDT 2008

On Thu, 10 Jul 2008 13:55:31 -0700, <carl.clawson@pkinetics.com> wrote:

> On Jul 10, 12:52 pm, Family Tree Mike
> <FamilyTreeM...@discussions.microsoft.com> wrote:
>> It would seem to make sense that you would have issues if you don't
>> dispose
>> something that can be disposed.
>
> I don't expect to have to dispose things explicitly unless there's a
> reason that I need to have it done at a specific point in the code.
> That's what the garbage collector is for.

This is categorically WRONG.

Jack's reply addresses this, but because it's so important, let me be very
clear: if an object implements IDisposable, it's _essential_ that you call
Dispose() on the object when you're done with it. The garbage collector
is for releasing _managed_ memory. _Disposing_ objects is the exact
opposite of "what the garbage collector is for".

Pete

Re: StatusStrip control leaks its collection items by Jonas

Jonas
Thu Jul 10 21:33:52 CDT 2008

On 7=D4=C211=C8=D5, =C9=CF=CE=E79=CA=B100=B7=D6, "Peter Duniho" <NpOeStPe..=
.@nnowslpianmk.com>
wrote:
> On Thu, 10 Jul 2008 13:55:31 -0700, <carl.claw...@pkinetics.com> wrote:
> > On Jul 10, 12:52 pm, Family Tree Mike
> > <FamilyTreeM...@discussions.microsoft.com> wrote:
> >> It would seem to make sense that you would have issues if you don't =
=20
> >> dispose
> >> something that can be disposed.
>
> > I don't expect to have to dispose things explicitly unless there's a
> > reason that I need to have it done at a specific point in the code.
> > That's what the garbage collector is for.
>
> This is categorically WRONG.
>
> Jack's reply addresses this, but because it's so important, let me be ver=
y =20
> clear: if an object implements IDisposable, it's _essential_ that you cal=
l =20
> Dispose() on the object when you're done with it. The garbage collector =
=20
> is for releasing _managed_ memory. _Disposing_ objects is the exact =20
> opposite of "what the garbage collector is for".
>
> Pete

1. Create a UserControl
2. add a ToolStrip to the UserControl
3. add a ToolStripTextBox(or a ToolStripComboBox) to the UserControl
4. Create a form and add the UserControl to the form(remeber as Class
Form2)
5.Create another form(remeber as Class Form1)
6. add a button1 to form1.
7.create button1_Click
private void button1_Click(object sender, EventArgs e)
{
using (Form2 f =3D new Form2())
{
f.ShowDialog();
}
}

evertime click the button to show Form2,u can see GDI objects+1(Use
Windows Task Manager)

in this case,do i need Dispose this ToolStripTextBox=A3=BF

Re: StatusStrip control leaks its collection items by carl

carl
Thu Jul 10 23:37:16 CDT 2008

On Jul 10, 6:00=A0pm, "Peter Duniho" <NpOeStPe...@nnowslpianmk.com>
wrote:
> On Thu, 10 Jul 2008 13:55:31 -0700, <carl.claw...@pkinetics.com> wrote:
> > I don't expect to have to dispose things explicitly unless there's a
> > reason that I need to have it done at a specific point in the code.
> > That's what the garbage collector is for.
>
> This is categorically WRONG.
>
> Jack's reply addresses this, but because it's so important, let me be ver=
y =A0
> clear: if an object implements IDisposable, it's _essential_ that you cal=
l =A0
> Dispose() on the object when you're done with it. =A0The garbage collecto=
r =A0
> is for releasing _managed_ memory. =A0_Disposing_ objects is the exact =
=A0
> opposite of "what the garbage collector is for".
>
> Pete

Sorry Pete, but I don't agree. Look at the standard Dispose/Finalize
pattern. like here: http://msdn.microsoft.com/en-us/library/s9bwddyx.aspx.
You'll see that when a disposable object is finalized, its unmanaged
resources are released. That's what the Dispose(False) in the
finalizer does. You need to dispose it only if you need to control
WHEN the unmanaged resources get released, or if you need to force
managed resources to be released before they would otherwise get
finalized. A good example is if you've opened a stream on a file and
need to re-open it. If you don't Dispose (or Close) the old stream,
you have to wait an unpredictable amount of time before the file will
open again because you've left a stream hanging around with an open
file handle that won't close until the garbage collector gets to it.

Now, it's certainly a good idea to dispose things when you're done
with them. No argument there. But I don't get why it's absolutely
necessary, and I've never had a problem until I bumped into the
StatusStrip. The finalizer will eventually take care of it as long as
all references to the object are gone. I would say that any finalizer
that fails to do so is buggy. There may be some special cases with
system-wide resources that don't get released on program exit because
I don't think finalizers always get called on exit. But that's not
what we're talking about here.

Theoretical arguments aside, I can do the very same experiment with
any other control, like buttons. Create a bunch, put them on a form,
take them off. Repeat indefinitely. You can watch the handle count
grow and then suddenly drop back repeatedly as the unused buttons get
garbage collected. So...why can I get away with not disposing buttons,
but I can't get away with not disposing ToolStripItems? I tried this
with a form full of buttons just now and the handle count never rises
much above 100 before dropping back down to a dozen or two.

-- Carl

Re: StatusStrip control leaks its collection items by Peter

Peter
Fri Jul 11 00:23:21 CDT 2008

On Thu, 10 Jul 2008 21:37:16 -0700, <carl.clawson@pkinetics.com> wrote:

>> [...] _Disposing_ objects is the exact  
>> opposite of "what the garbage collector is for".
>>
>> Pete
>
> Sorry Pete, but I don't agree. Look at the standard Dispose/Finalize
> pattern. like here:
> http://msdn.microsoft.com/en-us/library/s9bwddyx.aspx.
> You'll see that when a disposable object is finalized, its unmanaged
> resources are released.

That's true. But there's no guarantee that an object will _ever_ be
finalized, never mind when.

> That's what the Dispose(False) in the
> finalizer does. You need to dispose it only if you need to control
> WHEN the unmanaged resources get released,

But that's all the time. There's not ever a situation in which correct
code can leave disposal of unmanaged resources up to the indeterminate
rules offered by the garbage collector.

> [...]
> Now, it's certainly a good idea to dispose things when you're done
> with them. No argument there. But I don't get why it's absolutely
> necessary,

It's absolutely necessary because without managing the disposal of
unmanaged resources yourself you have no guarantee they will ever be
managed, nor do you have any deterministic behavior regarding the disposal
and other cleanup of unmanaged resources.

> and I've never had a problem until I bumped into the
> StatusStrip. The finalizer will eventually take care of it as long as
> all references to the object are gone.

Again, there is no guarantee that this will happen.

> I would say that any finalizer
> that fails to do so is buggy.

You would be wrong then. The finalizer does exactly what it's documented
to do, but finalizing objects isn't part of its guarantee.

> [...]
> Theoretical arguments aside, I can do the very same experiment with
> any other control, like buttons. Create a bunch, put them on a form,
> take them off. Repeat indefinitely. You can watch the handle count
> grow and then suddenly drop back repeatedly as the unused buttons get
> garbage collected. So...why can I get away with not disposing buttons,
> but I can't get away with not disposing ToolStripItems? I tried this
> with a form full of buttons just now and the handle count never rises
> much above 100 before dropping back down to a dozen or two.

I can't answer the specific question because I don't have a concrete code
sample with which to compare, nor do I really care. The fact is, since
.NET never guarantees that an object will be finalized, and since you are
required by the .NET contract to dispose objects that implement
IDisposable, the fact that you leak resources when you fail to dispose
such objects is a bug in your code, not in .NET.

Disagree all you want. The fact remains that by your own admission, if
you'd followed the .NET requirement of disposing disposable objects, you
wouldn't have a problem. That may not be incontrovertible proof, but it's
sure a heck of a strong suggestion.

Pete

Re: StatusStrip control leaks its collection items by Peter

Peter
Fri Jul 11 00:25:11 CDT 2008

On Thu, 10 Jul 2008 19:33:52 -0700, Jonas Yans <jonas.yans@gmail.com>
wrote:

> [...]
> private void button1_Click(object sender, EventArgs e)
> {
> using (Form2 f = new Form2())
> {
> f.ShowDialog();
> }
> }
>
> evertime click the button to show Form2,u can see GDI objects+1(Use
> Windows Task Manager)
>
> in this case,do i need Dispose this ToolStripTextBoxï¼?

No. Disposing its parent takes care of disposing it.

Re: StatusStrip control leaks its collection items by carl

carl
Fri Jul 11 09:49:26 CDT 2008

>
> Disagree all you want. =A0The fact remains that by your own admission, if=
=A0
> you'd followed the .NET requirement of disposing disposable objects, you =
=A0
> wouldn't have a problem. =A0That may not be incontrovertible proof, but i=
t's =A0
> sure a heck of a strong suggestion.
>
> Pete

I agree that garbage collection is non-deterministic. No argument
there. I also agree that calling Dispose when possible is a very good
practice. It's what I normally do.

But I still maintain that an object that wraps an unmanaged resource
must release that resource in its finalizer. If the finalizer never
gets called, so be it. The object can't help that.

Now back to the problem at hand, I am finding that controls removed
from the StatusStrip appear to either A) never get finalized, which
means a reference to them is probably being held somewhere because
other deleted controls ARE getting finalized, or B) they are getting
finalized but not releasing their handles. OK, per our discussion,
point "A" is not an absolute proof of a problem, but it's pretty darn
good evidence. I remain convinced that there IS a problem with these
controls!

Thanks for the explanations, Pete.
-- Carl


Re: StatusStrip control leaks its collection items by Peter

Peter
Fri Jul 11 11:38:44 CDT 2008

On Fri, 11 Jul 2008 07:49:26 -0700, <carl.clawson@pkinetics.com> wrote:

> I agree that garbage collection is non-deterministic. No argument
> there. I also agree that calling Dispose when possible is a very good
> practice. It's what I normally do.

It's not just "very good practice". It's mandatory for correct code.

As an example, here's a quote from MSDN: "To provide explicit control,
implement the Dispose provided by the IDisposable. The consumer of the
object should call this method when it is finished using the object." And
from the same page "Note that even when you provide explicit control using
Dispose, you should provide implicit cleanup using the Finalize method.
Finalize provides a backup to prevent resources from permanently leaking
if the programmer fails to call Dispose."
http://msdn.microsoft.com/en-us/library/b1yfkh5e.aspx

They aren't saying that implementing IDisposable provides an optional
approach to managing unmanaged resources. They are saying that if an
object goes to the trouble of implementing IDisposable, then the user of
that object is expected to call Dispose() when they're done with it, and
that the finalizer exists in order to prevent incorrect code from creating
permanent problems.

> But I still maintain that an object that wraps an unmanaged resource
> must release that resource in its finalizer. If the finalizer never
> gets called, so be it. The object can't help that.

You are confusing two different issues. An object that maintains
unmanaged resources must implement a finalizer, and must release those
unmanaged resources in the finalizer. So you got that part correct.
However, the finalizer doesn't exist for correct code. It exists for
incorrect code. That is, it's a backup plan for dealing with code that is
buggy.

In a bug-free program, a finalizer of an object implementing IDisposable
is never called.

> Now back to the problem at hand, I am finding that controls removed
> from the StatusStrip appear to either A) never get finalized, which
> means a reference to them is probably being held somewhere because
> other deleted controls ARE getting finalized,

Without a complete program there is no way to know for sure why your
controls aren't getting finalized. But that's not relevant. The fact is,
your own code has absolutely no business _relying_ on finalization. You
_must_ dispose the controls yourself if you expect your code to work
correctly and reliably.

Now, you may in fact find that even if you call Dispose(), you still have
a bug somewhere. For example, if the controls are actually still being
referenced somewhere else, and something tries to access them after
they're disposed, an exception will probably be thrown.

But at least you'll know that the code that thinks it's cleaning up the
controls is disposing them properly.

In fact, if anything this illustrates why relying on the non-deterministic
behavior of finalization is such a bad idea. It pushes other bugs farther
out, making them harder to find and fix.

Pete

Re: StatusStrip control leaks its collection items by carl

carl
Fri Jul 11 12:21:13 CDT 2008

On Jul 11, 9:38=A0am, "Peter Duniho" <NpOeStPe...@nnowslpianmk.com>
wrote:
>
> It's not just "very good practice". =A0It's mandatory for correct code.
>

Yes. I was trying to make a point and got a bit carried away. The
essential fact that I skated right over, is that the garbage collector
doesn't care about handles or other non managed resource. It will
clean up the memory when it thinks it needs to, and the handles will
get released at that point, if and when that happens.

> However, the finalizer doesn't exist for correct code. =A0It exists for =
=A0
> incorrect code. =A0That is, it's a backup plan for dealing with code that=
is =A0
> buggy.
>

Yes. That is a much more clear statement of what I was trying to say
when I said something like "that's what the garbage collector is for."
For the record, I hate nondeterminism and struggle against it
constantly. Anyhow, I'm an old C++ guy, so I'm used to cleaning up
after myself.

Never forget the old NASA saying: "Once you start depending on a
backup system, it's not a backup system any more." Even though I've
found the GC to be pretty darn good at, um, hiding my mistakes from
me, it is not good to depend on it.

>
> In fact, if anything this illustrates why relying on the non-deterministi=
c =A0
> behavior of finalization is such a bad idea. =A0It pushes other bugs fart=
her =A0
> out, making them harder to find and fix.
>
> Pete

Yep. This was pretty hard to find, all right!

Let's just say that the StatusStrip and its items are for some unknown
reason less well behaved than other Windows Forms controls in this
regard. I am not the only person to have had trouble with them.
Anyhow, I no longer have a problem so I don't plan to goof around with
them any more.

Thanks for making me stop a moment and think clearly.
Carl