I have a Windows Forms app that itself launches different threads to do different kinds of work. Occasionally, ALL threads (including the UI thread) become frozen, and my app becomes unresponsive. I've decided it may be a Garbage Collector-related issue, as the GC will freeze all managed threads temporarily. To verify that just managed threads are frozen, I spin up an unmanaged one that writes to a "heartbeat" file with a timestamp every second, and it is not affected (i.e. it still runs):
public delegate void ThreadProc();
[DllImport("UnmanagedTest.dll", EntryPoint = "MyUnmanagedFunction")]
public static extern void MyUnmanagedFunction();
[DllImport("kernel32")]
public static extern IntPtr CreateThread(
IntPtr lpThreadAttributes,
uint dwStackSize,
IntPtr lpStartAddress,
IntPtr lpParameter,
uint dwCreationFlags,
out uint dwThreadId);
uint threadId;
ThreadProc proc = new ThreadProc(MyUnmanagedFunction);
IntPtr functionPointer = Marshal.GetFunctionPointerForDelegate(proc);
IntPtr threadHandle = CreateThread(IntPtr.Zero, 0, functionPointer, IntPtr.Zero, 0, out threadId);
My Question is: how can I simulate this situation, where all managed threads are suspended but unmanaged ones keep on spinning?
My first stab:
private void button1_Click(object sender, EventArgs e) {
Thread t = new Thread(new ThreadStart(delegate {
new Hanger();
GC.Collect(2, GCCollectionMode.Forced);
}));
t.Start();
}
class Hanger{
private int[] m_Integers = new int[10000000];
public Hanger() { }
~Hanger() { Console.WriteLine("About to hang...");
//This doesn't reproduce the desired behavior
//while (true) ;
//Neither does this
//Thread.Sleep(System.Threading.Timeout.Infinite);
}
}
Thanks in advance!!
Finalizers are executed concurrently with "normal" thread execution. We usually say that the GC runs the finalizers, but it would be truer that the GC detects which instances have finalizers which should be run, and stores them in a dedicated queue. A (hidden) thread fetches the instances from the queue and runs the finalizers. Such asynchronism is needed, e.g. because the finalizers may themselves allocate memory and potentially trigger a GC. There are other good reasons why finalizers are necessarily asynchronous.
Bottom-line is that you cannot alter, from ~Hanger(), what the VM does during a GC pause, because the thread which will actually run ~Hanger() is also paused at that time.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With