Garbage collection occurs when one of the following conditions is true:
- The system has low physical memory.
- The memory that is used by allocated objects on the managed heap
surpasses an acceptable threshold. This threshold is continuously
adjusted as the process runs.
- The GC.Collect method is called. In almost all cases, you do not
have to call this method, because the garbage collector runs
continuously. This method is primarily used for unique situations
and testing.
Also the garbage collector tracks memory only on the managed heap, so for this program, the only condition can trigger GC is the first one.
I compiled the program, if the target CPU is x86, it will through out of memory exception when the private bytes of the process reaches about 2G. When I run the program, I noticed the private bytes increase quickly, but the working set increase very slowly, and also the system physical memory usage increase very slowly.
As private bytes and working set, this post explains:
Private Bytes refer to the amount of memory that the process executable has asked for - not necessarily the amount it is actually using. They are "private" because they (usually) exclude memory-mapped files (i.e. shared DLLs). But - here's the catch - they don't necessarily exclude memory allocated by those files. There is no way to tell whether a change in private bytes was due to the executable itself, or due to a linked library. Private bytes are also not exclusively physical memory; they can be paged to disk or in the standby page list (i.e. no longer in use, but not paged yet either).
Working Set refers to the total physical memory (RAM) used by the process. However, unlike private bytes, this also includes memory-mapped files and various other resources, so it's an even less accurate measurement than the private bytes. This is the same value that gets reported in Task Manager's "Mem Usage" and has been the source of endless amounts of confusion in recent years. Memory in the Working Set is "physical" in the sense that it can be addressed without a page fault; however, the standby page list is also still physically in memory but not reported in the Working Set, and this is why you might see the "Mem Usage" suddenly drop when you minimize an application.
Marshal.AllocHGlobal just increases the private bytes, but the working set is still small, it doesn't trigger GC either.
Please refer this: Fundamentals of Garbage Collection