Are there possible remaining big RAM usage we might not be aware of?
Yes. Actually GC.Collect()
does not collect all the allocated memory. It only collects generations 0,1,2 that are all "small" objects.
Note: it's not even clear as to whether GC.Collect()
always causes a full garbage collection of generations 0,1 and 2. People have varying strategies to deal with it but I don't want to elaborate on this since I don't have the final answer and it seems to depend on .NET versions.
There is another heap Large Object Heap, sometimes called the 4th heap (or even 3rd generation which is not a good name) where all objects with size >85000 are allocated.
This heap has a completely different functioning. Read for example:
The Large Object Heap appears to be reserved by the process (by Windows) while it is actually full of "holes" that can be used by new (large) objects and are seen as free by the C# memory manager.
The Large Object Heap cannot be compacted manually before .NET 4.5.1. It only happens when the CLR needs/wants it.
Whether the CLR compacts the LOH often or not depends on what garbage collector you use. Typically the server GC, used by default in ASP.NET, does not compact the LOH. Actually this is true for .NET 4.5 but might have evolved in next versions. The strategies to manage the LOH tend to evolve quite a bit in .NET versions. Not every detail that were explained once remain true.
As far as I know this might be the main cause of observing several GBs of remaining RAM (that are not memory leaks). Most often this is not a problem. You'll find a lot more here: When is memory, allocated by .NET process, released back to Windows