tags:

views:

325

answers:

6

Summary

We have to understand which part of our (or third party, probably CLR itself) code leads to boxing of integers.

Problem description

We have a rather big application where we observe high allocation rate of System.Int32 instances. With the help of Memory Profiler we see a small number of long existing Int32 instances (18, to be exact) and 20-25 thousands of Int32 allocations per second. All those objects are GC collected as Gen0 objects, system has no memory leaks and can be run for long time. When memory snapshot is created, GC is executed before snapshot, so snapshot does not contains any traces of those “temporary” objects.

All our code was specifically written to eliminate boxing whenever possible, and “by design” we are supposed to not see boxings at all. So we suspect it is some non-eliminated forgotten boxing in our code, or boxing caused by third-party component and/or CLR type itself.

System is compiled using VS2008, and uses .Net 3.5 (measurements were done in both debug and release builds, with the same behavior).

Question

How can we (using windbg, VS2008, Memory Profiler, AQTime or any other commercially available product) detect why boxing happens ?

+1  A: 

Have you made a static analysis of your code? Maybe NDepend can help you to find the methods and types that are boxing and unboxing values.

A trial version of NDepend is freely available, so it would be worth trying to analyze the assemblies, both yours and 3rd party.

Jehof
We have license for NDepend, but it is not convenient to use it for this purpose - we have many "potential" boxing (in error logging framework, for instance), that never happen in actual scenario. In addition, NDepend doesn't pinpoint source line where problem occurs.Anyhow, in this specific case problem was tracked back to CLR code.
Alex
A: 

I think GlowCode can report where boxing of value types is occurring, although you need to trawl through the options to find out how to turn it on.

Colin Desmond
A: 

A very low tech, but surprisingly effective approach is to attach a debugger and every so often hit pause, and see where the program stops.

If you are allocating a sufficient amount of time to trigger a great deal of GC activity then you stand a good chance of breaking in the code where the boxing allocation occurs.

This has the advantage of needing no new tools (assuming you have a decent IDE or Debugger)

ShuggyCoUk
A: 

Boxing and unboxing operations can be detected by static analysis of your code. Look for fxcop rules.

A profiler might be able to help you also, since so many allocations per seconds will surely cause a lot of overhead.

Good luck and keep us posted on your results.

Pat
I'll try static analysis tools, although they won't catch boxing originating in CLR / third party components. Turns out we have NDepends license, so I'll give it a tryProfiler doesn't show anything significant, total CPU is also very low. Looks like those allocations / collections are rather cheap from CPU cycles point of view.
Alex
+2  A: 

One of my favorite applications is CLR Profiler this will give you what you are looking for it will map your entire application showing the different generations. It's a free download from Microsoft and it's extremely powerful and simple to use. I have also included a link for how to use it. (CLR Profiler Download) (How to Use CLR Profiler)

ewrankin
CLR Profiler displayed it in allocations view. It took very long time to capture the heap, and it almost crashed on our tiny test app, but still helped us to solve the puzzle.Problem was tracked back to CLR code - see update in my question.
Alex
I should have mentioned that CLR Profiler is very intrusive from a performance standpoint. So that should always be in the back of a person's mind when using it. Regardless it's a great tool to have.
ewrankin
+1  A: 

Rather surprisingly, methods of DateTime class ToLocalTime/ToUniversalTime cause boxing.

Our application (application server) was recently modified to work "inside" in UTC only (to cope with daylight time changes etc). Our client codebase stayed 99% local time based.

Application server converts (if needed) local times to UTC times before processing, effectively causing boxing overhead on every time-related operation.

We will consider re-implementing those operations "in house", without boxing.

Alex