Duplicate object graph
Your application uses ~ 1.1 GB of virtual memory from .NET. You can see that from the exit !eeheap -gc directly
GC Heap Size: Size: 0x448fde94 (1150279316) bytes.
or by summing the values !dumpheap -stat .
Summing up all sizes (8500 lines of output lines) gives (1.1 GB)
This roughly corresponds to the value displayed as <unknown> in !address -summary .
--- Usage Summary ---------------- RgnCount ------- Total Size -------- %ofBusy %ofTotal <unknown> 2043 58997000 ( 1.384 Gb) 71.43% 69.22%
There is no reason to assume that the entire object graph is duplicated. This is a normal situation.
Outofmemory
At the moment, there is 65 MB of virtual memory already allocated by .NET and marked as free (from !dumpheap -stat ):
004b0890 159 65181140 Free
Unfortunately, these 65 MB are divided into 159 small regions. to get the largest block of them, you need to run !dumpheap -mt 004b0890 .
In addition, .NET can get another 63 MB from Windows (from !address -summary ):
--- Usage Summary ---------------- RgnCount ------- Total Size -------- Free 518 3f6b000 ( 63.418 Mb)
But the largest block is only 1.6 MB, so it's almost useless:
--- Largest Region by Usage ----------- Base Address -------- Region Size ---------- Free 7752f000 1a1000 ( 1.629 Mb)
So, obviously, the application has lost memory.
Where is the memory located?
252 MB are in the native heap. You seem to be using some native dlls. Although at the moment this does not seem too strong, this fact may indicate the presence of fixed objects. Attached objects are not collected with garbage. Look at the output !gchandles to find out if this might be part of the problem.
188 MB are in the DLL. You can unload your own DLL files that are not used, but for .NET collections you probably can't do much.
125 MB are in packages. With a default size of 1 MB, it seems that your application has 125 threads. Use !clrstack to find out what they are doing and why they are not done yet. Potentially, each thread is working on something and has not yet freed objects. If you have this under your control, do not start so many threads in parallel. For instance. use only 8 threads and wait for the threads to complete before doing the next part of the work.
Of course, most of the memory is used by .NET objects. However, you have made several incorrect conclusions.
As I understand it, there is not a single object that takes up all the memory. The largest is only about 122 MB.
Note that there are no EffectiveValueEntry[] objects containing 122 MB of memory. Of these, 847,783. This changes the question: "Why does this object use so much memory?" "Why are there so many?" For example, why does your application need text blocks 207.806? Does it really display so much text?
Using !gcroot is a good idea. However, you used it with the address of the method table instead of the object:
!gcroot 6848038c !gcroot 6708fd04
These were both numbers from the output !dumpheap -stat . Using them in !gcroot should give a warning, for example
Please note that 6848038c is not a valid object.
Instead !gcroot only works with individual objects that you get from !dumpheap without the -stat parameter.
You can use !traveseheap filename.log to delete all objects in a file compatible with the CLR profiler [Codeplex] . Note that the CLR Profiler cannot read the -xml format. After loading the Heap Graph object information, itβs probably the most useful button for you.
To find out about an OutOfMemoryException exception trigger, you can use the !u command. You will need to read the MSIL code to understand what it does. See Also How to determine the type of an array . However, in your scenario, I assume this is useless, because even small objects can cause this.