Memory stream

I am trying to track a memory leak in a larger C # program that generates multiple threads. In the process, I created a small side program that I use to test some basic things, and I found some behavior that I really don't understand.

class Program { static void test() { } static void Main(string[] args) { while (true) { Thread test_thread = new Thread(() => test()); test_thread.Start(); Thread.Sleep(20); } } } 

By running this program, I see that the memory usage in the program is constantly increasing without stopping. In a few minutes, memory usage is well over 100 MB and continues to grow. If I comment on the line test_thread.Start (); the memory used by the program will go out by about a few megabytes and will be aligned. I also tried to force garbage collection at the end of the while loop to use GC.Collect (), but it did nothing.

I thought the thread would be dereferenced as soon as the function was finished to allow the GC to hide it, but this does not seem to be happening. I should not understand something deeper here, and I would appreciate help in fixing this leak. Thanks in advance!

+6
source share
1 answer

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.

+9
source

Source: https://habr.com/ru/post/974861/


All Articles