This is by design, your test program should demonstrate the use of runaway memory. You can see the main reason from Taskmgr.exe. Use View + Select Columns and check "Handles". Watch how the number of pens for your process is constantly increasing. Memory usage grows with this, reflecting the unmanaged memory used by handle objects.
The design choice was very bold, the CLR uses 5 operating system objects per thread. Plumbing used for synchronization. These objects themselves are disposable; the design choice was not to make the Thread class an IDisposable implementation. This would be quite a challenge for .NET programmers; it is very difficult to make a Dispose () call at the right time. Courage that was not presented in the design of the Task btw class, causing a lot of manual bending and general advice not to disturb .
This is usually not a problem in a well-developed .NET program. Where the GC works often enough to clear these OS objects. Thread objects are created sparingly using ThreadPool for very short current threads, like your test program.
It may be, we cannot see your real program. Beware of drawing too many conclusions from such a synthetic test. You can see the GC statistics using Perfmon.exe, gives you an idea if it works often enough. An example would be a good .NET profiler. GC.Collect () is a backup weapon. For instance:
static void Main(string[] args) { int cnt = 0; while (true) { Thread test_thread = new Thread(() => test()); test_thread.Start(); if (++cnt % 256 == 0) GC.Collect(); Thread.Sleep(20); } }
And you will see that it goes back and forth, never getting much more than 4 MB.
source share