I have a 'service' (owin/webapi + odp.net managed) that runs with the 'server gc mode' on x64 machine. After executing test suite memory usage was around 2Gb. I 'generated' memory pressure on that machine (another program that consumed all available memory and more). I was expecting that windows will force .net to release some memory. However it did not. Here is an output from windbg:
0:018> !dumpheap -stat
Statistics:
MT Count TotalSize Class Name
00007ffd10445b90 1 24 System.Collections.Generic.GenericEqualityComparer`1[[System.UInt64, mscorlib]]
...
00007ffd0f904918 100864 11616976 System.Object[]
0000005b19face20 84 1810674044 Free
Total 720544 objects
Fragmented blocks larger than 0.5 MB:
Addr Size Followed by
0000005b1c3c8800 425.6MB 0000005b36d56c50 System.Func`2[[System.IAsyncResult, mscorlib],[System.Net.HttpListenerContext, System]]
0000005c1c3fcf00 28.2MB 0000005c1e02be58 System.Reflection.Emit.MethodBuilder
0000005c1e02e5b0 268.0MB 0000005c2ec313d8 System.Threading.OverlappedData
0000005c2ec31678 142.3MB 0000005c37a830a0 System.Func`2[[System.IAsyncResult, mscorlib],[System.Net.HttpListenerContext, System]]
0000005d1c541aa0 404.8MB 0000005d35a1a958 System.Func`2[[System.IAsyncResult, mscorlib],[System.Net.HttpListenerContext, System]]
0000005d35a1e5a8 3.8MB 0000005d35df0c40 System.Func`2[[System.IAsyncResult, mscorlib],[System.Net.HttpListenerContext, System]]
0000005e1cfe7128 444.1MB 0000005e38c0c3f0 System.Byte[]
0000005e38c8cfb8 4.5MB 0000005e39110988 System.Byte[]
0000005e39111bf8 1.2MB 0000005e3923a570 System.Byte[]
0000005e3923b7e0 0.7MB 0000005e392ed7d0 System.Byte[]
0000005e392eea40 1.1MB 0000005e39401910 System.Byte[]
0:018> !heapstat
Heap Gen0 Gen1 Gen2 LOH
Heap0 455256040 24 24 3713672
Heap1 464550872 24 4327776 727456
Heap2 428541352 10344768 12616 24
Heap3 474250128 24 21350456 24
Total 1822598392 10344840 25690872 4441176
Free space: Percentage
Heap0 446429064 0 0 1819552SOH: 98% LOH: 48%
Heap1 459823968 0 144 152SOH: 98% LOH: 0%
Heap2 428520936 34904 24 24SOH: 97% LOH:100%
Heap3 474044952 0 336 24SOH: 95% LOH:100%
Total 1808818920 34904 504 1819752
So there is only around 48Mb really used and 1.8Gb free, most of memory is not in LOH but in Gen 0 heap, but .net would not give that memory back. And meanwhile system was starving for memory. For example IIS failed to start because there were not enough memory.
Why memory was not reclaimed by windows?
Well windows cannot "force" .Net to free memory. While I am no expert in the .Net runtime my experience has been that the .net framework will hold onto memory once your application starts to consume a lot of it. It will slowly give it back as it see's fit. From windows perspective it doesn't really know what .Net will do with it but it .Net has claimed that memory from the OS and so until it (.net) gives it back windows cannot give that memory to another application. There are several 400+mb chunks of System.Byte[] that are being held onto, which could be indicative of a memory leak. From the OS's perspective the Framework has requested the memory and even used that memory so until it is explicitly (from the framework not you) given back windows cannot do anything about it. I would profile your application very carefully because generally the reason .Net isn't releasing memory is because you have a memory leak. Using the memory analysis tools in Visual Studio should show you if you are leaving memory "Pinned" or just holding on to it. Really bad culprites are often static class variables/events.
SO link: .NET Free memory usage (how to prevent overallocation / release memory to the OS)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With