473,486 Members | 1,640 Online
Bytes | Software Development & Data Engineering Community
Create Post

Home Posts Topics Members FAQ

.NET 1.1 (and possibly 1.0 also) Threads leaking "Event" handles. [BUG??]

Hi,

Threads in the .NET Framework 1.1 (and possibly in 1.0 also) leak "Event"
handles, by Event handles I mean Win32 Event handles which can be monitored
using the ProcessExplorer from www.sysinternals.com, or even simply look at
the Handle count in the good old windows TaskManager.
To demonstrate the problem, all I did was created a basic Win Forms
application and with Main implemented as:

[STAThread]
static void Main()
{
Application.Run(new Form1());
}

and Form's constructor as
public Form1()
{
while(true)
{
Thread thread = new Thread( new ThreadStart( ThreadProc) );
thread.Start();
Thread.Sleep(1000);
GC.Collect();
}
}
and the ThreadProc is implemented simply as
protected void ThreadProc()
{
Thread.Sleep(100);
return;
}

Now you let it run for a while and monitor the handle count using the
ProcessExplorer or TaskManager to can see that the thread count becomes more
or less constant after a bit (which means that an equilibrium is reached in
which the threads being created and thread which die is same), you will note
that the Handle count keeps on increasing. I have monitored upto 10000
handles after which I killed the application.
Now, this seems like a bug. Has someone got any explaination for this and
possibly a workaround. BTW, I also tried changing the attribute on Main from
STAThread to MTAThread with no change in behavior.
Any help/suggestions would be appreciated.

thanks,
Rohit
Jul 21 '05 #1
11 3608
Please, try this from a console type application, and you will see that
there are no 'event' handle leaks related to the Thread start delegate.
If there's a leak is somewhere else in your code, could you post a complete
repro sample.
Willy.

"Rohit" <no****@nospam.org> wrote in message
news:uM**************@TK2MSFTNGP11.phx.gbl...
Hi,

Threads in the .NET Framework 1.1 (and possibly in 1.0 also) leak "Event"
handles, by Event handles I mean Win32 Event handles which can be monitored using the ProcessExplorer from www.sysinternals.com, or even simply look at the Handle count in the good old windows TaskManager.
To demonstrate the problem, all I did was created a basic Win Forms
application and with Main implemented as:

[STAThread]
static void Main()
{
Application.Run(new Form1());
}

and Form's constructor as
public Form1()
{
while(true)
{
Thread thread = new Thread( new ThreadStart( ThreadProc) );
thread.Start();
Thread.Sleep(1000);
GC.Collect();
}
}
and the ThreadProc is implemented simply as
protected void ThreadProc()
{
Thread.Sleep(100);
return;
}

Now you let it run for a while and monitor the handle count using the
ProcessExplorer or TaskManager to can see that the thread count becomes more or less constant after a bit (which means that an equilibrium is reached in which the threads being created and thread which die is same), you will note that the Handle count keeps on increasing. I have monitored upto 10000
handles after which I killed the application.
Now, this seems like a bug. Has someone got any explaination for this and
possibly a workaround. BTW, I also tried changing the attribute on Main from STAThread to MTAThread with no change in behavior.
Any help/suggestions would be appreciated.

thanks,
Rohit

Jul 21 '05 #2
Rohit wrote:
Hi,

Threads in the .NET Framework 1.1 (and possibly in 1.0 also) leak
"Event" handles, by Event handles I mean Win32 Event handles which
can be monitored using the ProcessExplorer from www.sysinternals.com,
or even simply look at the Handle count in the good old windows
TaskManager.
To demonstrate the problem, all I did was created a basic Win Forms
application and with Main implemented as:

[STAThread]
static void Main()
{
Application.Run(new Form1());
}

and Form's constructor as
public Form1()
{
while(true)
{
Thread thread = new Thread( new ThreadStart( ThreadProc) );
thread.Start();
Thread.Sleep(1000);
GC.Collect();


I cannot see a _real_ problem with any of your sample code when you add
explict calls to GC.Collect /and/ GC.WaitForPendingFinalizers. Thread has a
Protected Finalize and does not implement the IDisposable interface, so its
unmanaged handles (which seem to correspond to a Win32 Thread handle and a
handful of Event handles) don't get cleaned up until the GC get around to it.
And with an infinite loop creating threads, your test isn't going to do GC
until it determines there's a pressing need to do so.

So it's not really a bug, just an 'interesting' design decision to not provide
IDisposable for Thread.

BTW Anyone got a good way of forcing a running .NET process' GC to do a
collection?
--
Regards,
Mark Hurd, B.Sc.(Ma.) (Hons.)

Jul 21 '05 #3
> BTW Anyone got a good way of forcing a running .NET process' GC to do a
collection?
GC.Collect() and GC.WaitForPendingFinalizers() will do it, but if you want
to reduce the working set you have to act on the Process class. Here's my
sample: http://blogs.geekdojo.net/richard/posts/338.aspx

Richard

--
C#, .NET and Complex Adaptive Systems:
http://blogs.geekdojo.net/Richard
"Mark Hurd" <ma******@ozemail.com.au> wrote in message
news:%2****************@TK2MSFTNGP10.phx.gbl... Rohit wrote:
Hi,

Threads in the .NET Framework 1.1 (and possibly in 1.0 also) leak
"Event" handles, by Event handles I mean Win32 Event handles which
can be monitored using the ProcessExplorer from www.sysinternals.com,
or even simply look at the Handle count in the good old windows
TaskManager.
To demonstrate the problem, all I did was created a basic Win Forms
application and with Main implemented as:

[STAThread]
static void Main()
{
Application.Run(new Form1());
}

and Form's constructor as
public Form1()
{
while(true)
{
Thread thread = new Thread( new ThreadStart( ThreadProc) );
thread.Start();
Thread.Sleep(1000);
GC.Collect();
I cannot see a _real_ problem with any of your sample code when you add
explict calls to GC.Collect /and/ GC.WaitForPendingFinalizers. Thread has

a Protected Finalize and does not implement the IDisposable interface, so its unmanaged handles (which seem to correspond to a Win32 Thread handle and a
handful of Event handles) don't get cleaned up until the GC get around to it. And with an infinite loop creating threads, your test isn't going to do GC
until it determines there's a pressing need to do so.

So it's not really a bug, just an 'interesting' design decision to not provide IDisposable for Thread.

BTW Anyone got a good way of forcing a running .NET process' GC to do a
collection?
--
Regards,
Mark Hurd, B.Sc.(Ma.) (Hons.)

Jul 21 '05 #4
Richard A. Lowe wrote:
BTW Anyone got a good way of forcing a running .NET process' GC to
do a collection?


GC.Collect() and GC.WaitForPendingFinalizers() will do it, but if you
want to reduce the working set you have to act on the Process class.
Here's my sample: http://blogs.geekdojo.net/richard/posts/338.aspx


Good stuff, but I'm refering to a running .NET sample like the one in this
thread. Is there a good way to get the GC to decide it should run even though
the process is busy.

I'm running the OP's sample code and it's got to over 21000 handles and I know
they're all ready for garbage collection. I assume I need to temporarily max
out one of the resources the GC monitors to determine when it should run
immediately, but I couldn't find a way that doesn't just cause random programs
to fail with out of memory errors...
--
Regards,
Mark Hurd, B.Sc.(Ma.) (Hons.)

Jul 21 '05 #5

"Rohit" <no****@nospam.org> wrote in message
news:OH**************@TK2MSFTNGP10.phx.gbl...
Hi Willy,
Thanks for your reply, I will try in a console application, however in the
meanwhile here is a small test app (basically its a win forms application in C#) that will demonstrate the problem. I have attached a zip file containing the whole project.
One quick note, this is a small app so I'm creating threads from inside the Form's constructor so you will not see the window come up (since the
initialization of the main form never completes). However this has no effect on the handle leak even if I were to start thread creation from outside.
thanks again,
Rohit


Ok I see, you do not call GC.Collect.
But what you observe is not a leak, in this small sample, the only objects
that get allocated on the GC heap are the Thread objects (~60 bytes/object),
Thread objects have an associated OS handle and a synchronization event
handle, so before the GC kicks in (for the second time) you will have
allocated thousands of them.
Now, in a real world application the GC will run more often and what you
observe now will not show up.

Willy.
Jul 21 '05 #6
Hi,
Thanks all for your input.
I had (before posting this question on this messageboard) played with
calling GC.Collect() and also GC.WaitForPendingFinalizers() explicitly, and
yes I do agree that in this small application the handles do get cleaned
out.
However, what actually prompted all this exercise is that in the product
that I'm working on we are seeing a similar handle leak. Now, thats a
remoting based application with a service running on the server side to
which client (one or more) connect and then do the stuff and then
disconnect. Now, in this application we are seeing a handle leak when we do
a regression testing. So, I started eliminating code to see what I find. So,
the smallest bit of code that still leaks handle goes like this:

A Singleton object is exposed remotly.
from another application, I make remoting calls, get this remote object, and
then call a method in this object. This method starts a thread, where in
ThreadProc is implemented like below and then returns.
protected void ThreadProc()
{
Thread.Sleep(1000);
GC.Collect();
return;
}
Even this code, despite my calling GC.Collect() is showing an increase in
handle count. And if I moniter using the new ProcessExplorer from
SysInternals.Com, which shows the number of GC calls (for Gen 0, 1 and 2),
or if I use PerfMon which also shows the GC calls, I see that the GC is
being called, but even then the handle count of thread and event objects is
growing.
Now, is it possible, that GC is ignoring (or in other words "incorrectly
handling") thread and event handles (i.e. objects of class Thread) and not
proper garbage collecting them, in a remoting scenario or in a scenario
where there are other objects to be collected it leaves behind the Thread
objects.
Any help in this regard would be greatly appreciated,
thanks,
Rohit

"Willy Denoyette [MVP]" <wi*************@pandora.be> wrote in message
news:ux**************@TK2MSFTNGP09.phx.gbl...

"Rohit" <no****@nospam.org> wrote in message
news:OH**************@TK2MSFTNGP10.phx.gbl...
Hi Willy,
Thanks for your reply, I will try in a console application, however in the meanwhile here is a small test app (basically its a win forms
application in
C#) that will demonstrate the problem. I have attached a zip file containing
the whole project.
One quick note, this is a small app so I'm creating threads from inside

the
Form's constructor so you will not see the window come up (since the
initialization of the main form never completes). However this has no

effect
on the handle leak even if I were to start thread creation from outside.
thanks again,
Rohit


Ok I see, you do not call GC.Collect.
But what you observe is not a leak, in this small sample, the only

objects that get allocated on the GC heap are the Thread objects (~60 bytes/object), Thread objects have an associated OS handle and a synchronization event
handle, so before the GC kicks in (for the second time) you will have
allocated thousands of them.
Now, in a real world application the GC will run more often and what you
observe now will not show up.

Willy.

Jul 21 '05 #7
Mark,

If you run OP's console sample (including GC.Collect(), you will see that
the GC run's every second.

Willy.

"Mark Hurd" <ma******@ozemail.com.au> wrote in message
news:OV**************@TK2MSFTNGP12.phx.gbl...
Richard A. Lowe wrote:
BTW Anyone got a good way of forcing a running .NET process' GC to
do a collection?
GC.Collect() and GC.WaitForPendingFinalizers() will do it, but if you
want to reduce the working set you have to act on the Process class.
Here's my sample: http://blogs.geekdojo.net/richard/posts/338.aspx


Good stuff, but I'm refering to a running .NET sample like the one in this
thread. Is there a good way to get the GC to decide it should run even

though the process is busy.

I'm running the OP's sample code and it's got to over 21000 handles and I know they're all ready for garbage collection. I assume I need to temporarily max out one of the resources the GC monitors to determine when it should run
immediately, but I couldn't find a way that doesn't just cause random programs to fail with out of memory errors...
--
Regards,
Mark Hurd, B.Sc.(Ma.) (Hons.)

Jul 21 '05 #8
"Rohit" <no****@nospam.org> wrote in news:#5vZu52vDHA.2520
@TK2MSFTNGP10.phx.gbl:

Here's what I ran:

using System;
using System.Threading;

class Class1
{
static void Main(string[] args)
{
while(true)
{
Thread thread = new Thread(new ThreadStart(ThreadProc));
thread.Start();
Thread.Sleep(1000);
GC.Collect();
}
}

static void ThreadProc()
{
Thread.Sleep(1500);
return;
}
}

No handle leak here.

Mark
Jul 21 '05 #9
Hi,
Thanks all for your input.
I had (before posting this question on this messageboard) played with
calling GC.Collect() and also GC.WaitForPendingFinalizers() explicitly, and
yes I do agree that in this small application the handles do get cleaned
out.
However, what actually prompted all this exercise is that in the product
that I'm working on we are seeing a similar handle leak. Now, thats a
remoting based application with a service running on the server side to
which client (one or more) connect and then do the stuff and then
disconnect. Now, in this application we are seeing a handle leak when we do
a regression testing. So, I started eliminating code to see what I find. So,
the smallest bit of code that still leaks handle goes like this:

A Singleton object is exposed remotly.
from another application, I make remoting calls, get this remote object, and
then call a method in this object. This method starts a thread, where in
ThreadProc is implemented like below and then returns.
protected void ThreadProc()
{
Thread.Sleep(1000);
GC.Collect();
return;
}
Even this code, despite my calling GC.Collect() is showing an increase in
handle count. And if I moniter using the new ProcessExplorer from
SysInternals.Com, which shows the number of GC calls (for Gen 0, 1 and 2),
or if I use PerfMon which also shows the GC calls, I see that the GC is
being called, but even then the handle count of thread and event objects is
growing.
Now, is it possible, that GC is ignoring (or in other words "incorrectly
handling") thread and event handles (i.e. objects of class Thread) and not
proper garbage collecting them, in a remoting scenario or in a scenario
where there are other objects to be collected it leaves behind the Thread
objects.
Any help in this regard would be greatly appreciated,
thanks,
Rohit

"Mark" <mark@--somewhere--.com> wrote in message
news:Xn******************************@207.46.248.1 6...
"Rohit" <no****@nospam.org> wrote in news:#5vZu52vDHA.2520
@TK2MSFTNGP10.phx.gbl:

Here's what I ran:

using System;
using System.Threading;

class Class1
{
static void Main(string[] args)
{
while(true)
{
Thread thread = new Thread(new ThreadStart(ThreadProc));
thread.Start();
Thread.Sleep(1000);
GC.Collect();
}
}

static void ThreadProc()
{
Thread.Sleep(1500);
return;
}
}

No handle leak here.

Mark

Jul 21 '05 #10
> "Mark Hurd" <ma******@ozemail.com.au> wrote in message
news:OV**************@TK2MSFTNGP12.phx.gbl...
Richard A. Lowe wrote:
> BTW Anyone got a good way of forcing a running .NET process' GC
> to do a collection?

Willy Denoyette [MVP] wrote: Mark,

If you run OP's console sample (including GC.Collect(), you will see
that the GC run's every second.


Yes. However, in the general case, say a test program or a threaded Mandelbrot
set generator, etc, can a system admin (not the programmer redesigning the
source) kick the GC into action externally?

In posing this question I was assuming the GC automatically checked other
Windows resources than memory (quite implicitly). Once I realised this is
probably not what an "Automatic memory management system" does, and I've
confirmed it:

Other than managed memory allocations, implementations of the
garbage collector do not maintain information about resources
held by an object, such as file handles or database connections.

(from About GC Class in the 1.1.1 docs.)

And yes, this is obvious in hindsight. I was just in a Windows frame of mind
when thinking about this.

So, I suppose it comes down to, "Is there an external API, or other 'hook',
(perhaps normally for debugging) that can initiate a GC?"
--
Regards,
Mark Hurd, B.Sc.(Ma.) (Hons.)

Jul 21 '05 #11
Mark Hurd wrote:
Rohit wrote:
Hi,

Threads in the .NET Framework 1.1 (and possibly in 1.0 also) leak
"Event" handles, by Event handles I mean Win32 Event handles which
can be monitored using the ProcessExplorer from
www.sysinternals.com, or even simply look at the Handle count in
the good old windows TaskManager.
To demonstrate the problem, all I did was created a basic Win Forms
application and with Main implemented as:

[STAThread]
static void Main()
{
Application.Run(new Form1());
}

and Form's constructor as
public Form1()
{
while(true)
{
Thread thread = new Thread( new ThreadStart( ThreadProc) );
thread.Start();
Thread.Sleep(1000);
GC.Collect();


I cannot see a _real_ problem with any of your sample code when you
add explict calls to GC.Collect /and/ GC.WaitForPendingFinalizers.
Thread has a Protected Finalize and does not implement the
IDisposable interface, so its unmanaged handles (which seem to
correspond to a Win32 Thread handle and a handful of Event handles)
don't get cleaned up until the GC get around to it. And with an
infinite loop creating threads, your test isn't going to do GC until
it determines there's a pressing need to do so.

So it's not really a bug, just an 'interesting' design decision to
not provide IDisposable for Thread.


I think Eric G has described the issue well here:

http://blogs.gotdotnet.com/EricGu/pe...2-6b1e3830988d

The difference being, the GDI wrappers can be Disposed, but Thread cannot.
--
Regards,
Mark Hurd, B.Sc.(Ma.) (Hons.)

Jul 21 '05 #12

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

0
7004
by: Andy Read | last post by:
Hello all, I have the requirement to produce source code that produces an object hierarchy. Example: Root | Folder 1
2
3864
by: Eddy Bee | last post by:
Hi there, I'm encountering an inexplicable problem with page formatting in reports. Here's the easiest way to explain it: The Detail section of my report contains two elements: And let's...
2
1460
by: lovecreatesbeauty | last post by:
Hello, I want to know whether programming languages such as C or C++ provide something like "event". In function "f1", a handler/function "h2" is triggered. But f1 won't be blocked by h2,...
15
2886
by: Billy | last post by:
Anyone know if this a bug in VB.NET 2002 and how to overcame that situation? I have a MDI form from where I call MDI child form like that: Dim frm As New frmChild() frm.MdiParent = Me...
11
370
by: Rohit | last post by:
Hi, Threads in the .NET Framework 1.1 (and possibly in 1.0 also) leak "Event" handles, by Event handles I mean Win32 Event handles which can be monitored using the ProcessExplorer from...
5
6462
by: Jason | last post by:
Hello, I am trying to dynamically create a table, then set its <td>'s onclick: var table = document.createElement("table"); var row = table.insertRow(-1); var td = row.insertCell(-1);...
0
1272
by: diff | last post by:
I am having trouble preventing a bound source from updating using event-driven validation. There is a very nice article on MSDN explaining this;...
6
7504
by: Gregor Kofler | last post by:
I'm trying to "detect" a keydown event in a DIV. The idea have a keydown listener attached to document and forward the event to the div. (I've searched the web, but it was impossible to handle...
1
1771
by: Fresno Bob | last post by:
I have a script manager in my Master Page. I want use the Ajax history functionality. This means code in my content page needs to be called when the navigate event fires in the master. How can I...
0
7094
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
6964
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
7173
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
1
6839
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
1
4863
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...
0
4559
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...
0
3066
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The...
0
3070
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
598
muto222
php
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.