views:

311

answers:

6

What is the overhead of generating a lot of temporary objects (i.e. for interim results) that "die young" (never promoted to the next generation during a garbage collection interval)? I'm assuming that the "new" operation is very cheap, as it is really just a pointer increment. However, what are the hidden costs of dealing with this temporary "litter"?

+7  A: 

Not a lot - the garbage collector is very fast for gen0. It also tunes itself, adjusting the size of gen0 depending on how much it manages to collect each time it goes. (If it's managed to collect a lot, it will reduce the size of gen0 to collect earlier next time, and vice versa.)

The ultimate test is how your application performs though. Perfmon is very handy here, showing how much time has been spent in GC, how many collections there have been of each generation etc.

Jon Skeet
Downvoters: comments are welcome, otherwise no-one (including me) will know what you disagree with about my answer...
Jon Skeet
Where do I get PerfMon?
Karl
It's almost certainly installed on your Windows box already. Hit Windows-R and just type "perfmon". Otherwise finding it will depend on which version of Windows you're using.
Jon Skeet
I had no idea you could use the performance monitor to monitor garbage collection. That could be useful.
Aaron Smith
There are vast numbers of perf counters for .NET. It's really impressive.
Jon Skeet
+3  A: 

As you say the allocation itself is very inexpensive. The cost of generating lots of short lived objects is more frequent garbage collections as they are triggered when generation 0's budget is exhausted. However, a generation 0 collection is fairly cheap, so as long as your object really are short lived the overhead is most likely not significant.

On the other hand the common example of concatenating lots of strings in a loop pushes the garbage collector significantly, so it all depends on the number of objects you create. It doesn't hurt to think about allocation.

The cost of garbage collection is that managed threads are suspended during compaction.

Brian Rasmussen
+1  A: 

In general, this isn't something you should probably be worrying about and sounds like it starts to fall very close to "micro-optimization". The GC was designed with an assumption that a "well tuned application" will have all of it's allocations in Gen0 - meaning that they all "die young". Any time you allocate a new object it is always in Gen0. A collection won't occur until the Gen0 threshold is passed and there isn't enough available space in Gen0 to hold the next allocation.

The "new" operation is actually a bunch of things:

  1. allocating memory
  2. running the types constructor
  3. returning a pointer to the memory
  4. incrementing the next object pointer
Scott Dorman
A: 

If these objects are never promoted out of Generation 0 then you will see pretty good performance. The only hidden cost I can see is that if you exceed your Generation 0 budget you will force the GC to compact the heap but the GC will self-tune so this isn't much of a concern.

Andrew Hare
A: 

Garbage collection is generational in .Net. Short lived objects will collect first and frequently. Gen 0 collection is cheap, but depending on the scale of the number of objects you're creating, it could be quite costly. I'd run a profiler to find out if it is affecting performance. If it is, consider switching them to structs. These do not need to be collected.

Michael Meadows
+1  A: 

Although the new operation is designed and written efficiently it is not free and does take time to allocate new memory. The memory allocation library needs to track what chunks are available for allocation and the newly allocated memory is zeroed.

Creating a lot of objects that die young will also trigger garbage collection more often and that operation can be expensive. Especially with "stop the world" garbage collectors.

Here's an article from the MSDN on how it works: http://msdn.microsoft.com/en-us/magazine/bb985011.aspx

Note: that it describes how calling garbage collection is expensive because it needs to build the object graph before it can start garbage collection.

scurial
From the linked article: "These tests also show that it takes less than 1 millisecond on a 200Mhz Pentium to perform a full GC of generation 0. It is Microsoft's goal to make GCs take no more time than an ordinary page fault." Hardly "very expensive" IMO. Not free, certainly, but if (cont.)
Jon Skeet
the code is more readable with lots of small, short-lived objects then I'd rather go that way until it was *proven* to be a bottle-neck than bend my design out of shape to counteract a performance "problem" which may not be a problem at all.
Jon Skeet
I agree and I'm not saying that they should change how they write programs. The question asked what the underlying overheads are, and I tried to provide an answer.
scurial
I also changes the comment about "very expensive" so it's not as strong. 1ms on a 200mhz chip is still hundreds of thousands of cycles and with the current memory wall problem GC on modern computers takes millions of CPU cycles.
scurial
Millions even for *just* a gen0 collection? That sounds like more than I'd expect. I'd be interested to read more though - do you have any references?
Jon Skeet
Here's a classic survey:PR Wilson, Uniprocessor garbage collection techniques, International Workshop on Memory Management. The paper surveys many GC algorithms and notes that GC typically adds an additional 5 - 20% runtime and 40 - 280% space overhead.
scurial
Here's another more recent article:http://www.cis.udel.edu/~cavazos/ismm-07.pdf"GC has a significant effect on overall execution time ... In the most extreme case, one configuration ... spent 89% of its execution time performing GC. The mean proportion of execution time spent inGC is 12.2% ..."
scurial