Why is this memory not cleared or not allocated at all?

So, I have this awesome program that is very useful:

static void Main(string[] args) { new Dictionary<int,int>(10000000); while (true) { System.Threading.Thread.Sleep(1000); } } 

This does not even cause any warnings from the compiler, which is surprising.

Running this allocation allocates a chunk of memory. If I run several copies, I will eventually get to the point where I can no longer start because I have run out of memory.

  • Why does the garbage collector never empty the memory, instead the system goes into a state in which there is not enough memory for new processes?
  • Why, why memory allocation is not optimized? You can never refer to it!

So what is going on here?

+4
source share
4 answers

The garbage collector is not deterministic and responds to memory pressure. If nothing requires memory, it may not be collected for a while. It cannot optimize new because it changes your code: the constructor may have side effects. In addition, when debugging, it most likely decides not to collect.

In a release / optimized build, I would expect this to happen at some point when there are good reasons. There is also GC.Collect , but this should generally be avoided, with the exception of extreme scenarios or certain profiling requirements.

Like β€œwhy,” there is a difference in the behavior of the GC between generations of GCs; and you have large arrays on the β€œbig object heap” (LOH). This LOH is quite expensive to keep checking, which may further explain why it is so reluctant.

+6
source

I assume that the hidden Gen0 collection is executing.

Here is my test program:

 static void Main(string[] args) { new Dictionary<int, int>(10000000); Thread.Sleep(5000); int x = 1; // or 0; int i = 0; while (true) { object o = ++i; Thread.Sleep(x); } } 

When the system executes Sleep (1), the system should think that this is the right time for a fast hidden GC on Gen0. Thus, the operator "object o = ++ i" never exerts pressure on Gen0 and never launches a GC collection and therefore never releases a dictionary.

Sleep (1) http://www.freeimagehosting.net/uploads/6fad1952e0.png

Change x to 0. Now this hidden GC does not occur, and everything works as expected with the operator 'object o = ++ i', which forces to compile a dictionary.

Sleep (0) http://www.freeimagehosting.net/uploads/f285b8acdb.png

+3
source

GC probably starts and frees up memory ... for the application itself. That is, if the call to Sleep() requires some RAM, then it will probably find a lot of it, namely the large blocks that were originally allocated for the huge Dictionary .

This does not mean that GC returns memory to the operating system. From an OS perspective, large blocks can still be part of the process, rather than being used by any other process.

Distribution is not optimized because it is some kind of external code. Your Main class calls the constructor for Dictionary<int,int> , which can do its best with various side effects. As a human programmer, you expect that the constructor will not have externally visible side effects, but the compiler and the virtual machine do not know this for sure. Thus, the code cannot do without creating an instance of Dictionary<int,int> and calling its constructor. Similarly, the Dictionary<int,int> constructor does not know that it is called for an object that will soon become inaccessible, so it will not be able to optimize itself.

0
source

I do not know this, but I would suggest, because even without creating a link to your new dictionary, it was connected to the local area at a time that your program never leaves. To check if this is true, just create a dictionary in the inner area that you can leave before starting your loop, for example

  static void Main (string [] args)
 {
     {
         new Dictionary (10000000);
     }

     while (true)
     {
         System.Threading.Thread.Sleep (1000);
     }
 } 

this should now leave memory available for garbage collection

-1
source

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


All Articles