The example code below allocates a large number of sync blocks. This is displayed in Performance Monitor as "# of sink blocks in use". However after releasing the locks, the counter will not decrease until I manually call GC.Collect()
. Why doesn't this happen automatic or isn't this a problem?
using System;
using System.Collections.Generic;
using System.Threading;
namespace locktest
{
public class Program
{
static void Main(string[] args)
{
var list1 = new List<Object>();
int threadcount = 0;
const int maxthreads = 9000;
for (int i = 0; i < maxthreads; i++)
{
var obj = new Object();
list1.Add(obj);
Monitor.Enter(obj); // this will initially use just a thin lock
// lock from a different thread to move to the sync blocks table
ThreadPool.QueueUserWorkItem(o =>
{
Monitor.TryEnter(o, 1);
Interlocked.Increment(ref threadcount);
}, obj);
}
while (threadcount < maxthreads)
Thread.Sleep(100); // wait until all threads have been finished
foreach (var obj in list1)
Monitor.Exit(obj); // release the locks
list1.Clear();
Console.WriteLine("Press enter to force GC.");
Console.ReadKey();
GC.Collect(); // this will reduce the number of sync blocks to almost 0
Console.WriteLine("Press enter to quit.");
Console.ReadKey();
}
}
}
related: What is a “Sync Block” and tips for reducing the count