3

Partly out of curiosity - we want to know what happens in our application - and partly because we need to find some potential issues in our code, I like to track some general values during runtime of our web applications. This includes especially the allocated memory of certain object graphs.

Our applications keeps some data permanently in memory to have it reliable available. This can sum up to several GB of memory, while other applications that do almost the same stuff only allocate one or two.

Due to required performance we cannot attach memory profilers during runtime. So it would be great to analyze an object graph at runtime to print out which parts of the data are so big in some cases and which are not so big. This would help us a lot to better understand what happens with the data and potentially optimize the behavior of our applications.

Object graph means, starting from a certain object, measuring its size in memory, recursively following all referenced objects through all properties, fields, lists with all their elements etc. and adding their corresponding size until we have the information how much memory is used by this object and all related objects.

Actually, the question I would like to have an answer for is: When I just release the last reference to this anchor object, how much would the GC be able to free up when cleaning this object graph with the next run?

Sebastian P.R. Gingter
  • 5,955
  • 3
  • 31
  • 73

2 Answers2

3

If you are not using a profiler you are up for a difficult task.

The question about measuring the size of an object graph has been raised on SO multiple times, e.g:

Ways to determine size of complex object in .NET?

How to get object size in memory?

Each question has received a bunch of answers (feel free to read through them) but to be honest they all suck more or less. You have to accept that there is no reliable way of getting this information, because it is an implementation detail.

But let's assume that what you actually need is not an accurate measurement but some ballpark figures to know where the "Big Boy Objects" are.

  • Serialize your object graph

A simple approach I can think of is serializing your objects with a binary formatter into a memory stream and check the size on that.

  • Use dump files

Another approach could be creating dump files of your application and using them to analyse the memory. Visual Studio 2013 has a new memory analyzer that helps you understand the .NET memory use of your applications from .dmp files collected on production machines.

It also shows you the size for all objects:

enter image description here

There is a two part introduction to this:

Part 1: http://blogs.msdn.com/b/visualstudioalm/archive/2013/06/20/using-visual-studio-2013-to-diagnose-net-memory-issues-in-production.aspx

Part 2: http://blogs.msdn.com/b/visualstudioalm/archive/2013/10/16/net-memory-analysis-enhancements-in-visual-studio-2013.aspx

  • Use Microsoft.Diagnostics.Runtime "CLR MD"

CLR MD is a C# API used to build diagnostics tools. It gives you the power and flexibility of what the SOS and PSSCOR debugger extensions can do in a simple, fast C# API.

The documenation on github has an example about a non-linear heap walker that is used to calculate the size of an object. It works the same as !objsize in SOS, so that this command takes an object as (a parameter and counts the number of objects it keeps alive as well as reports (the total size of all objects the given object keeps alive.

https://github.com/Microsoft/dotnetsamples/blob/master/Microsoft.Diagnostics.Runtime/CLRMD/docs/WalkingTheHeap.md

Community
  • 1
  • 1
Postlagerkarte
  • 6,600
  • 5
  • 33
  • 52
3

It's not clear whether this meets your requirements, but the SOS extension for Windbg provides the !objsize command to determine the size of an object recursively including all referenced objects. You can either attach to the running process, or take a memory dump (e.g. using procdump) and then attach to the dump file to perform the analysis offline. However the output from !objdump will only be the answer to your final question if the sub-objects are only reachable from your initial object (any other references will of course prevent the sub-object tree from being collected even if your initial object becomes unreachable).

The reason this so difficult from within the process itself is in part due to the fact that the runtime necessarily hides a lot of the detail with regards in-memory representations. Some of this can be overcome through the use of unsafe code, however it's still non-trivial, and so the use of something like SOS in Windbg which "knows" the internals of the CLR makes the process much easier, with the obvious limitation that it must be done from "outside" the process, rather than from within.

Iridium
  • 23,323
  • 6
  • 52
  • 74