2

I've read the other questions that come up when I ask about memory snapshots, but I might be too thick to really grasp it. I have a windows service that I can produce a memory leak in by doing a pretty straightforward data operation repeatedly. I've taken memory snapshots along the way, and I see that the number of roots is going up (from 2,100 after a successful start to 7,100 after 100 or so data operations). The snapshots were taken at the blue arrow marks:

enter image description here

Before the multiple data operations, the memory snapshot looks like this:

enter image description here

Afterwards, it looks like this:

enter image description here

We're using WCF for data transport and it would appear that Serialization is playing a part in this memory growth, but I don't know where to go from here. If I look at instances of RuntimeType+RuntimeTypeCache, the vast majority of instances look like this:

enter image description here

If anyone can help me figure out the next step to take, I would appreciate it immensely. We have a static instance that has a concurrent dictionary of ServiceHosts that I'm suspicious of, but I don't know how to confirm it.

EDIT:

This also seems significant and is in reference to ServiceHosts. Could we be enabling some unwise proxy generation and instance retention via this static relationship?

enter image description here

sonicblis
  • 2,926
  • 7
  • 30
  • 48
  • the RunTimeTypeCache is Reflection internal and used by Serialization. https://stackoverflow.com/questions/3065386/can-the-net-methodinfo-cache-be-cleared-or-disabled You cannot change anything to that. Running serialization in a different AppDomain is recommended there. XML Serialization uses dynamic created code, and code cannot be unloaded. It's reused. So is should not grow forever. If you want to optimize your own code, you should look for things, created by your own code, objects of types that you created yourself. – Holger Oct 21 '19 at 12:54
  • This is the same data operation happening over and over on the same data. If it's being reused, I shouldn't see any growth here at all, right? – sonicblis Oct 21 '19 at 14:28
  • It grows by the types used. If you load the same object types again, it shouldn't grow. It grows if you need new generics or new lambdas f.e. Why do you care so much ? With 2MBytes it's not a situation to worry about. This memory view is good to find memory leaks you created. - but you have no leak - you just want to know what's going on for curiosity. If you run this script very frequent, you can consider using a serialization-dll. https://stackoverflow.com/questions/934411/what-is-myassembly-xmlserializers-dll-generated-for This avoids creating a new dll at each startup. – Holger Oct 21 '19 at 15:50
  • A) I am loading the same types, but the memory footprint is growing, B) we're getting out of memory exceptions on our production server, this isn't just for fun. – sonicblis Oct 21 '19 at 16:44
  • 1
    But don't look at this one only. Look for your data objects. This "OperationDescription" is also very large. Check the memory when it reaches 1GByte, (1.000.000.000 Bytes), then you can be more sure, to see the responsible objects. You can also call GC.Collect(), in between two read operations to be sure any allocated object is released. Are you sure, you re-use your XmlSerializer ? Or do you create a new one every time. I know this is more about serialization, than "how to read this window". But we cannot understand the entire .net framework to say "why it is allocating this or that". – Holger Oct 21 '19 at 17:03
  • We are using DataContractSerializers, but your question pointed me in the direction of where we DO use an XmlSerializer and we were creating a new one each time we needed it (and it wasn't caching because we were passing in known types to the constructor). We created a concurrent dictionary to hold those instead, and the memory creep disappeared. It might be indirect, but I'm very grateful. I'm not sure if there's an answer that would be helpful for anyone else in this, but if you want to add one, I'll accept it. – sonicblis Oct 21 '19 at 18:04
  • thank you, I try to summarize. It's most often just some kind of brainstorming or asking the right questions. – Holger Oct 21 '19 at 20:43

1 Answers1

0

Sort your items by Size, and inside that list, watch out for your own class types. Which one is piling up. Have at least a total of a few Megabytes of objects, to be sure to see a real 'Pile' not just some parts of the infrastructure.

The 12.000 existing runtime types, might indicate dynamically created types, maybe the serialization DLL is created for each new call.

You can also try to do GC.Collect() after your critical function call, to enforce Garbage collection.

Holger
  • 2,446
  • 1
  • 14
  • 13