If I run the simple method on Unit Test, which generates instances using unmanaged resource, for example bitmap, memory keeps increasing. In the case of executing the method in Thread
or ThreadPool
, the result is same. But if I run using Task.Run()
, GC works properly and memory is not increased.
What is the difference of GC operation between Task.Run
and others context?
[TestMethod]
public void Test()
{
//1. GC didn't work.
Work();
//2. GC didn't work.
//new Thread(() =>
//{
// Work();
//}).Start();
//3. GC didn't work.
//ThreadPool.QueueUserWorkItem((obj) =>
//{
// Work();
//});
//4. GC didn't work
//new Action(() =>
//{
// Work();
//}).BeginInvoke(null, null);
//5. GC works.
//Task.Run(() =>
//{
// Work();
//});
Thread.Sleep(Timeout.Infinite);
}
private void Work()
{
while (true)
{
GC.Collect();
var bitmap = new Bitmap(1024, 768);
Thread.Sleep(10);
}
}
First case memory log.
PrivateBytes : 282.0MB, AllHeapsBytes : 3.5MB, Thread Count : 32, CPU Usage : 12% PrivateBytes : 499.0MB, AllHeapsBytes : 2.8MB, Thread Count : 33, CPU Usage : 16% PrivateBytes : 734.0MB, AllHeapsBytes : 2.9MB, Thread Count : 33, CPU Usage : 11% PrivateBytes : 959.0MB, AllHeapsBytes : 3.0MB, Thread Count : 33, CPU Usage : 14% PrivateBytes : 1173.0MB, AllHeapsBytes : 3.1MB, Thread Count : 33, CPU Usage : 10% PrivateBytes : 1389.0MB, AllHeapsBytes : 2.9MB, Thread Count : 33, CPU Usage : 12% PrivateBytes : 1597.0MB, AllHeapsBytes : 2.9MB, Thread Count : 33, CPU Usage : 9% Exception thrown: 'System.ArgumentException' in System.Drawing.dll An exception of type 'System.ArgumentException' occurred in System.Drawing.dll but was not handled in user code Parameter is not valid.
5th case memory log
PrivateBytes : 41.0MB, AllHeapsBytes : 3.5MB, Thread Count : 32, CPU Usage : 16% PrivateBytes : 41.0MB, AllHeapsBytes : 2.9MB, Thread Count : 33, CPU Usage : 13% PrivateBytes : 41.0MB, AllHeapsBytes : 2.9MB, Thread Count : 33, CPU Usage : 14% PrivateBytes : 41.0MB, AllHeapsBytes : 2.9MB, Thread Count : 33, CPU Usage : 12% PrivateBytes : 41.0MB, AllHeapsBytes : 2.9MB, Thread Count : 33, CPU Usage : 14%
--- Updated ---
GC.Collect() doesn't collect immediately. When I call GC.Collect(), the GC will run each object's finalizer on a separate thread.
For GC working immediately, I should add GC.WaitForPendingFinalizers() after calling GC.Collect().
https://www.developer.com/net/csharp/article.php/3343191/C-Tip-Forcing-Garbage-Collection-in-NET.htm
But still I don't understand why GC works in Task.Run context.
--- Updated 2 ---
When I run this code in simple winform project, GC works properly and memory does not grow.