Handles leak (Event type) in .NET application
c#, handles, memory-leaks, multithreading, thread-synchronization
Solution
This answer is a bit late, but I just ran across the question while investigating a very similar issue in some of my code and found the answer by placing a break point at the syscall in the disassembly of CreateEvent. Hopefully other people will find this answer useful, even if it is too late for your specific use case.
The answer is that .NET creates Event kernel objects for various threading primitives when there is contention. Notably, I have made a test application that can show they are created when using the "lock" statement, though, presumably, any of the Slim threading primitives will perform similar lazy creation.
It is important to note that the handles are NOT leaked, though an increasing number may indicate a leak elsewhere in your code. The handles will be released when the garbage collector collects the object that created them (eg, the object provided in the lock statement).
I have pasted my test code below which will showcase the leak on a small scale (around 100 leaked Event handles on my test machine - your mileage may vary).
A few specific points of interest:
Once the list is cleared and the `GC.Collect()` is run, any created handles will be cleaned up.
Setting ThreadCount to 1 will prevent any Event handles from being created.
Similarly, commenting out the `lock` statement will cause no handles to be created.
Removing the `ThreadCount` from the calculation of `index` (line 72) will drastically reduce contention and thus prevent nearly all the handles from being created.
No matter how long you let it run for, it will never create more than 200 handles (.NET seems to create 2 per object for some reason).
using System.Collections.Generic;
using System.Threading;
namespace Dummy.Net
{
public static class Program
{
private static readonly int ObjectCount = 100;
private static readonly int ThreadCount = System.Environment.ProcessorCount - 1;
private static readonly List<object> _objects = new List<object>(ObjectCount);
private static readonly List<Thread> _threads = new List<Thread>(ThreadCount);
private static int _currentIndex = 0;
private static volatile bool _finished = false;
private static readonly ManualResetEventSlim _ready = new ManualResetEventSlim(false, 1024);
public static void Main(string[] args)
{
for (int i = 0; i < ObjectCount; ++i)
{
_objects.Add(new object());
}
for (int i = 0; i < ThreadCount; ++i)
{
var thread = new Thread(ThreadMain);
thread.Name = $"Thread {i}";
thread.Start();
_threads.Add(thread);
}
System.Console.WriteLine("Ready.");
Thread.Sleep(10000);
_ready.Set();
System.Console.WriteLine("Started.");
Thread.Sleep(10000);
_finished = true;
foreach (var thread in _threads)
{
thread.Join();
}
System.Console.WriteLine("Finished.");
Thread.Sleep(3000);
System.Console.WriteLine("Collecting.");
_objects.Clear();
System.GC.Collect();
Thread.Sleep(3000);
System.Console.WriteLine("Collected.");
Thread.Sleep(3000);
}
private static void ThreadMain()
{
_ready.Wait();
while (!_finished)
{
int rawIndex = Interlocked.Increment(ref _currentIndex);
int index = (rawIndex / ThreadCount) % ObjectCount;
bool sleep = rawIndex % ThreadCount == 0;
if (!sleep)
{
Thread.Sleep(10);
}
object obj = _objects[index];
lock (obj)
{
if (sleep)
{
Thread.Sleep(250);
}
}
}
}
}
}
Problem
I have a Windows Forms application written in .NET 4.0. Recently, while execution some tests, I noticed that there is some problem with handles. Table below shows the results: As you can see the, only handle type which is increasing is `Event`. So my question is: Is it possible that the described problem is caused by a Windows Forms application? I mean, I do not synchronize threads using `AutoResetEvent` or `ManualResetEvent`. I do use threads, but what can be seen from the table above the number of thread handles seems to be ok. So, I assume that they are well managed by CLR? Can it be caused by any third party components I am also using in my app? If sth is unclear I will try to answer your questions. Thanks for help!