7

We are testing a 4-process WCF IIS application (x3 release versions) for memory stability (leaks) by simply pinging it every ~1s as a Load Balancer might. It runs fine for >12hours if nothing else is running on the server.

However if we purposely reduce the total available memory (fixing the page, reduce physical memory, launch other apps) and push the physical memory usage to 97% and leave it there for 5 minutes or more, oftentimes Windows will sense the condition and shutdown one of the processes. Note it also fails if the total memory is pushed to 97% (by using a fixed page file).

However, analyzing the memory footprint of one of the surviving processes using the RedGate tool, shows this:

RedGate Summary Tab

Since the requests are just a steady ping, there seems to be no practical reason for .NET to hold the 269MB free memory when the server is starved. About 50% of the IIS Processes appear to be in this state (~1.8GB).

The App is compiled against .NET 4.0, gcServer true. IIS Gate checking was set to 0% (minFreeMemoryPercentageToActivateService="0") although we would probably set it to 2% in production.

The Server is 2008 R2, ~4GB physical 4GB fixed page, was tested with 4.0 and then 4.5.1 (didn't matter).

There is an answer to a similar question by @atanamir claiming:

".NET will free its heap back to the OS once you're running low on physical memory."

Anyone know of any reference for that claim? Could it be version specific?

Refs:

Community
  • 1
  • 1
crokusek
  • 5,345
  • 3
  • 43
  • 61
  • We later found this link on [gcTrimCommitOnLowMemory](https://msdn.microsoft.com/en-us/library/bb384209%28v=vs.100%29.aspx?f=255&MSPPError=-2147217396). We tried it in the aspnet.config, machine.config and system web.config. It seemed to have some effect in the system web.config but yet at 95% commit area still some processes where using 2X as much as others (when they all should be near same) and it seems to give up on trimming. – crokusek Mar 03 '15 at 19:07

2 Answers2

7

This is not exactly an answer to the question you asked (why) but it should be a way to achieve what you’re trying to do.

There is something new with .NET Framework 4.5 - source

Once a site is running, its use of the garbage-collector (GC) heap can be a significant factor in its memory consumption. Like any garbage collector, the .NET Framework GC makes tradeoffs between CPU time (frequency and significance of collections) and memory consumption (extra space that is used for new, freed, or free-able objects). For previous releases, we have provided guidance on how to configure the GC to achieve the right balance. For the .NET Framework 4.5, instead of multiple standalone settings, a workload-defined configuration setting is available that enables all of the previously recommended GC settings as well as new tuning that delivers additional performance for the per-site working set. For example, there is no need to set gcServer, gcConcurrent, etc.

Also here they state:

Tuning GC for high-density Web hosting: GC can impact a site’s memory consumption, but it can be tuned to enable better performance. You can tune or configure GC for better CPU performance (slow down frequency of collections) or lower memory consumption (that is, more frequent collections to free up memory sooner) […] in order to achieve smaller memory consumption (working set) per site

To enable GC memory tuning, add the following setting to the Windows\Microsoft.NET\Framework\v4.0.30319\aspnet.config file and Windows\Microsoft.NET\Framework64\v4.0.30319\aspnet.config file:

<configuration>
<!-- ... -->
<runtime>
<performanceScenario value="HighDensityWebHosting"  />
<!-- ... -->  

Basically, based on the tests I made, I saw that it will consume more CPU, less memory and make the GC to be more aggressive in terms of clean up and memory release process. We tested this setting within our infrastructure (IIS 7.5, new 4.5 framework) and the results were impressive. High memory usage leading to out of memory exceptions are no more an issue.

Hope it helps.

Cedricc
  • 96
  • 1
  • 5
1

The information given by atanamir can be found on this MSDN page.

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.

itsme86
  • 19,266
  • 4
  • 41
  • 57
  • 3
    But is Garbage Collection really the same as "releasing back to the OS"? – crokusek Feb 19 '15 at 19:06
  • 2
    @crokusek Yes, Did you even read the page that I linked for you? If you did, you'd see this (emphasis mine): **The garbage collector also** reserves segments as needed, and **releases segments back to the operating system** (after clearing them of any objects) by calling the Win32 VirtualFree function. – itsme86 Feb 19 '15 at 19:24
  • 1
    No, I skipped the link, thinking the pertinent parts were quoted in the answer. Your comment is helpful and it was not my downvote. However the question headline is about why the "releases segments back to the OS" is not happening as advertised. – crokusek Feb 19 '15 at 20:05
  • @itsme86 You wrote: "The garbage collector also reserves segments as needed, and releases segments back to the operating system" - that's oversimplifying: on x64 a .NET CLR memory segment will be 2GB, so the .NET CLR must be satisfied that the entire 2GB segment is no-longer in-use before it will release it back to the OS. Of course, unused memory pages ([pages are typically either 4KB or 2MB](https://devblogs.microsoft.com/oldnewthing/20210510-00/?p=105200)) will be _paged out_ by the OS eventually, even without the CLR informing Windows of page or segment usage. – Dai May 10 '22 at 07:30