C # thread memory usage

I learned more about streaming processing, and I created a fairly simple WPF application with the following code (x64 platform build)

public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); for (var i = 0; i <= 20000; i++) { Thread thread = new Thread(Test); thread.IsBackground = true; thread.Start(); } } public void Test() { Thread.Sleep(20000); } } 

When I run this code, the process takes approximately 560 MB of RAM, while all threads are running / down.

Highest peak

Upon completion of the process, the use of the process is reduced to 125 MB of RAM.

My question is, why is the process using 125 MB of RAM at the moment when the application itself (without the thread example) is using only 30 MB of RAM?

Does it support some of the threads for possible reuse or something else?

EDIT:

Due to some suggestions for improving this code, I would like to point out that I am not asking for its improvement, but to determine the reason for this behavior.

EDIT 2:

This is not thread related, but I tried the case with a large string list in memory, and it did not give the same results. When the list was fully loaded into memory, it took about 1.3 GB of memory, but after the list was set to NULL and GC.Collect() was called, memory usage dropped to 30 MB as expected.

code:

 public partial class MainWindow : Window { List<string> stringArray = new List<string>(); public MainWindow() { InitializeComponent(); for (var i = 0; i <= 100000000; i++) { //Thread thread = new Thread(Test); //thread.IsBackground = false; //thread.Start(); stringArray.Add("Some very long string to pump up the memory volume 2 reloaded"); } stringArray = null; GC.Collect(); } } 

Lowest peak

+5
source share
3 answers

The portion of memory used by each thread is freed when the thread terminates. Therefore, memory consumption drops from 560 MB to 125 MB when all background threads are completed.

The rest of the memory is allocated on the managed heap and will be freed by the garbage collector.

When your application is idle, no new memory is allocated, so the garbage collector does not need to be run. You mentioned in a comment that forcing GC using GC.Collect() did not help, but keep in mind that Thread has a finalizer, so it will survive in the first collection. You will need to use

 GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); 

to free up memory.

This should reduce memory usage to a level before starting threads.

+7
source

You are using a 64-bit application that just creates a lot of threads. First, it’s important to know that launching a Debug build of an application can produce different results than running a Release build because variables are artificially stored longer than they are needed in memory. Therefore, they will not be assembled as soon as possible.

The garbage collector is highly optimized and will fire when:

  • Gen0 has been fully allocated (Gen0 size is based on heuristics, such as the speed at which your application performs allocation, etc.);
  • Available memory runs out;
  • Called by GC.Collect.

The reason the GC does not collect memory is as fast as you thought, because there is simply no reason for the GC to collect memory. If your application runs on a 32-bit platform, it will still have 1.5 GB of memory. In your case, you are using a 64-bit application: a lot of memory is available. However, if you use a β€œreal” application with much more memory allocation, you will have a different result and probably a lot more collections (and therefore a smaller working set).

Finally, calling GC.Collect is often unnecessary and can ruin the GC heuristic, which can greatly affect the performance of your application, since GC.Collect initiates the collection of all generations.

https://msdn.microsoft.com/en-us/library/xe0c2357(v=vs.110).aspx

+2
source

Your streaming mechanism is part of the problem. Besides the fact that it takes so much processor time at runtime (which reduces the possibility of garbage collection), he saw how your memory usage is.

Something like this (minus debugging information) will be very economical to use your memory consumption. And your processor should be "loafing" during the operation (a static keyword from my testing in a console application) .. Net framework 4.0 or higher. If you are limited to permeable versions of .net, I would suggest a short pause before you start a new task to let garbage collection do this magic.

 private static void ThreadStuff() { long startSet = System.Diagnostics.Process.GetCurrentProcess().WorkingSet64; List<long> endSet = new List<long>(); for (var i = 0; i <= 20000; i++) { Action Act = new Action(() => Test(i)); Task Tsk = new Task(Act); Tsk.Start(); endSet.Add(System.Diagnostics.Process.GetCurrentProcess().WorkingSet64); int worker; int ioCompletion; ThreadPool.GetMaxThreads(out worker, out ioCompletion); Console.WriteLine(worker); Console.WriteLine(ioCompletion); } Console.WriteLine(startSet.ToString("###,###,###,###,###,###.####")); Console.WriteLine(endSet.Average().ToString("###,###,###,###,###,###.####")); } public static void Test(int Index) { Thread.Sleep(2000); Console.WriteLine(Index.ToString() + " Done"); } 
0
source

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


All Articles