.NET process memory usage = 5x CLR Heap Memory?

2019-02-10 17:20发布

问题:

I'm trying to tackle down some memory usage issues. Overall my application collects a few data values and visualizes them using a C1 WPF charts and datagrids finally putting everything into PDF reports.

Profiling my process using YourKit I'm faced with the situation, that the CLR heap size is ~120MB (which is all fine) while the process memory size is ~580MB. This is nearly 5 times the memory consumption of my actual CLR heap size. My CLR peak size was 220MB vs. 710MB process memory allocation.

I'm well aware that there is some overhead required on my object heap, stacks and so on. In Java JVMs the typical factor I'm used to was around ~1.5x.

How can this excessive memory overhead be explained? Is the processs just allocating free spare heap space? If yes, does this explain the 710MB vs. 220MB?

回答1:

A couple of additional notes here. Though I'm not exaclty sure what you mean by "CLR Heap Size". There about 8 different heaps that the CLR uses - so the memory you see in the Heap Size vs. VM size accounts for some of the difference:

  1. Loader Heap: contains CLR structures and the type system
  2. High Frequency Heap: statics, MethodTables, FieldDescs, interface map
  3. Low Frequency Heap: EEClass, ClassLoader and lookup tables
  4. Stub Heap: stubs for CAS, COM wrappers, P/Invoke
  5. Large Object Heap: memory allocations that require more than 85k bytes
  6. GC Heap: user allocated heap memory private to the app
  7. JIT Code Heap: memory allocated by mscoreee (Execution Engine) and the JIT compiler for managed code
  8. Process/Base Heap: interop/unmanaged allocations, native memory, etc

Two other items which can cause excessive memory usage are memory fragmentation (mostly occurs on the LOH or large object heap) or a high number of Threads.

There are many causes for memory fragmentation and the best way to rule this out is to use WinDbg to analyze the segment sizes for each segment on the GC Heap.

As far as a high number of threads, you have 1MB of stack space allocated for each thread that your app uses. This memory is placed in the Process/Base Heap. Therefore if you have 100 threads, you will have an additional 100MB of memory usage.

HTH



回答2:

If the total size of the managed heaps is significantly smaller than the private bytes used by your application it's likely that you're allocating unmanaged memory and (possibly) not disposing of it properly. Graphic objects, streams and other objects that implement IDisposable need to have their Dispose() method called before they go out of scope or be placed with in a using(){} statement so that any unmanaged resources get cleaned up. Using a tool like ANTS Memory Profiler can show you how your memory is being allocated and which objects implement IDisposable.