.NET Garbage Collection PopQuiz


Time for a little pop-quiz/potential interview questions to get some action going in the comments section… 

Feel free to answer any or all of the below questions, I’ll follow up with a post later if all of them are not answered…

 

1. How many GC threads do we have in a .NET process running the Server version of the GC on a dual-core machine?

2. What GC mode is used in the web development server (cassini) on a quad proc machine? Why?  (you can choose from server, workstation or concurrent-workstation)

3. How many finalizer threads do we have in a .NET process running the Server version of the GC on a quad proc machine?

4. When is an object garbage collected?

5. What causes an object to move from Generation 0 to Generation 1 or to Generation 2?

6. If you look at the GC sizes for Generation 0, 1 and 2 in perfmon, why is most of the memory in the process in Gen 2?

7. How many heaps will you have at startup on a 4 proc machine running the server GC?  How many would you have if the same machine was running the workstation GC?  Will the memory used for these show up in private bytes or virtual bytes in perfmon or both?

8. (Leading question:))  Is the fact that you have mscorwks.dll loaded in the process in 2.0 an indication of that you are running the workstation version of the GC?

9. Can you manually switch GC modes for a process?  If so, how and under what circumstances?

10. Name at least 2 ways to make objects survive GC collections unneccessarily.

11. Can a .NET application have a *real* memory leak?  In the C++ sense where we allocate a chunk of memory and throw away the handle/pointer to it?

12. Why is it important to close database connections and dispose of objects? Doesn’t the GC take care of that for me?  

 

and if you don’t think these questions are enough… feel free to post some of your own questions on the same theme…

Have fun,

Tess







Comments (25)

  1. 1/ 4 gc threads, one per processor.

    2/ I think that it would be workstation, since it is basically a winforms application.

    3/ Either one or four, although I am leaning toward one.

    4/ Um, during garbage collection? Not sure I understand the question.

    5/ A GC that runs but find that it is still rooted somewhere will promite it to the next generation.

    6/ Gen 2 also include the large objects, no?

    7/ No idea

    8/ Yes.

    9/ Define GC modes, you mean workstation vs server? If so, I believe that the answer is no. If it is possible, probably via obscure COM API.

    10/ Static Event Handlers, Cache[Guid.NewGuid()] = new object()

    11/ Yes, usually via calling unmanaged API.

    12/ It does, in the finalizer thread, which takes a _long_ time to process things. Basically this shove stuff like connection pooling out of the window, not to mention that basically resources are held for much longer.

  2. 1) 2 threads

    2) Workstation,

    3) 4

    4) Out of scope

    5) Allocation triggers GC and it causes live objects to promote from 0 to 1 or 1 to 2

    6) Long lived and big objects(8 kb) promoted to generation  2

    7) server GC -> 4 heaps and workstation GC -> 1 heap and initially it will be private bytes

    8) Yes

    9) For individual process answer is no, but we can set GC mode for machine, it is usually done for Winform application on multicore machines 

    10) A) Implement destructor and write resurrect pattern for that object. b) Declare object globally so unless and until appdomin is not unloaded it will survive.

    11) Yes

    12) GC is able to release manage memory only and database connection you can visualize as tunnel from manage world to OS, so if IDisposable is implemented and you don’t call Close() than at some time if GC happen (at least 2) than it might close that connection.

  3. I make mistake in my previous ans, I get confused between Server mode and concurrent-workstation mode

    1->1 Thread

    3 ->1

    7-> In both cases 1 heap only

  4. Stefan Wenig says:

    1 – I somehow gathered that the server GC interupts the current thread, that would mean zero. Not sure though.

    2 – Agree with Rahien.

    3 – cbrumme wrote about it, but I forgot it. One?

    4 – When there is no reference to it and any finalizing is done.

    5 – Agree with Rahien.

    6 – It has all objects of any serious life time. 0 and 1 have a fixed (small) size and pass their stuff to 2.

    7 – How would the number of procs or the GC type affect the number of heaps? One, or maybe one per app domain. (The allocated address range should show up in virtual bytes, the actually memory in private bytes. But don’t take my word for that.)

    8 – yes

    9 – Only through hosting APIs before any managed code gets executed.

    10 – Keep references in static structures, do not unregister for finalization (that would prevent collection only once), fixing it for interop …

    11 – If it could, i’d definately like to hear about it! (I don’t think unmanaged stuff counts)

    12 – The GC generally doesn’t care about anything but memory, so running out of connections won’t trigger it. Also, there are situations where you need resources freed immediately, e.g. if you need to access the resource again using another managed wrapper. Files and DB records could remain locked without disposing.

  5. X.Static says:

    Currently interviewing for a .Net PFE position w/ you guys, so I should know all of these, so here goes:

    1. Two, one per CPU

    2. Don’t know, but if I had to guess I’d say Concurrent GC…that’s the one I’d want used if I had a choice.

    3. ?

    4. You never know for sure, but it’s marked for GC when it’s reference count equals zero.

    5. When it "survives" a GC, i.e. it still has references to it when the GC is invoked.

    6. These are the objects with the most references to them, as well as the "large object heap."

    7. Guessing… 4. 1. Private bytes.

    8. No. mscorsvr was folded into mscorwks for the 2.0 release.

    9. I have no idea. I’m assuming you can via config sections, but the process will need to be restarted.

    10. Pin them via managed C++? That’s the only one I know of.

    11. Yes (kinda), objects can be orphaned but they won’t hang around forever.

    12. In the case of a database connection, that is an unmanaged resource and thus needs to be cleaned up in Dispose (finalizers). Only objects containing references to unmanaged resources should have dispose called on them.

  6. Bob says:

    1/ It’s dual core, so only 2

    3/ 1

    10/ Give it an unnecessary finalizer

  7. Greg D says:

    1. How many GC threads do we have in a .NET process running the Server version of the GC on a dual-core machine?

    — How many dual core processors are in the machine?  Are the cores hyperthreaded?  My understanding is that there will be one GC thread per logical CPU on the server version of the GC, so if it’s a single dual core processor without hyperthreading, I’d expect 2.  With hyperthreading, I’d expect 4.

    2. What GC mode is used in the web development server (cassini) on a quad proc machine? Why?  (you can choose from server, workstation or concurrent-workstation)

    — I don’t know, but I’d guess either server or concurrent workstation.  If it’s a webdev server with multiple processors, we’re expecting multiple users with notable load.  We want to take advantage of all that CPU power.

    3. How many finalizers do we have in a .NET process running the Server version of the GC on a quad proc machine?

    — I believe there’s still only one finalizer thread.  Is there one thread per application or AppDomain?  Or are applications defined by their AppDomain?

    4. When is an object garbage collected?

    — When a garbage collection takes place and the object has no remaining references.  (Perhaps surprisingly, this may result in an object being GC’d before it looks like it’s gone out-of-scope.)

    5. What causes an object to move from Generation 0 to Generation 1 or to Generation 2?

    — I believe an object is promoted through the generations when it survives a garbage collection at its current generation.  (A gen1 object won’t be promoted to gen2 on a gen0 collection).

    6. If you look at the GC sizes for Generation 0, 1 and 2 in perfmon, why is most of the memory in the process in Gen 2?

    — I’m not really certain.  I know that Gen2 collections don’t happen very often and gen2 should hold all information that lives as long as the process.  Perhaps System.String objects end up in Gen2 because of the flyweight pattern that they use in the CLR?

    7. How many heaps will you have at startup on a 4 proc machine running the server GC?  How many would you have if the same machine was running the workstation GC?  Will the memory used for these show up in private bytes or virtual bytes in perfmon or both?

    — I don’t know.  I suppose I’m not as well-versed as I ought to be in the differences between the GC flavors.

    8. (Leading question:))  Is the fact that you have mscorwks.dll loaded in the process in 2.0 an indication of that you are running the workstation version of the GC?

    — I don’t think so.  I recall reading somewhere that all flavors were merged into the one file for 2.0.  

    9. Can you manually switch GC modes for a process?  If so, how and under what circumstances?

    — I don’t know.  If you can, I’d be interested in knowing the reasoning behind the feature.  I can’t think of a use-case off the top of my head.

    10. Name at least 2 ways to make objects survive GC collections unneccessarily.

    — (A) Implement a useless finalizer.  (B) Keep references hanging around when you’ll never use them again and the CLR has no way of determining that they’ll never be used again.  Perhaps by forgetting to unpin some memory?

    11. Can a .NET application have a *real* memory leak?  In the C++ sense where we allocate a chunk of memory and throw away the handle/pointer to it?

    Yes, .net applications can make calls against unmanaged, leaky code.

    12. Why is it important to close database connections and dispose of objects? Doesn’t the GC take care of that for me?  

    It’s important to dispose the objects because it prevents the unnecessary promotion of the entire disposable object graph to a higher generation for finalization.

  8. Stefan Wenig says:

    1 – what was I thinking, even with all threads frozen, this would still mean that GC needs dedicated threads, one per processor would be the logical answer. 4, then.

  9. Phil says:

    Bottom line, none of this should really matter to the developer. Just be sure to close and dispose of all your objects and let .Net worry about the clean up. In the instance where memory management becomes an issue, the cause is usually a call to an unmanaged API that you have no control over any way (Thanks Crystal Reports). If you are really concerned about memory management, use the USING (){} statement and call the GC after major events in the code. Oh, did I mention be sure to close and dispose of your objects?

  10. Mark says:

    Great questions but to point 11 I wonder if you could do something like this

    unsafe

    {

    }

    and do as much memory leaking as you like!

  11. Arnaud Weil says:

    Interesting questions, and I’d love to get the answer for several of them!

    4. When the object gets unreferenced and the GC runs. To make things clear: an unreferenced object in the heap will not get garbage-collected until the GC runs.

    5. Objects that are still referenced when the GC runs move from gen 0 to gen 1. And so forth.

    6. Obviously, these are long-run objects since they weren’t GC’ed for quite a long period. Obviouly too, there will lay the open forms of my application and shared objects, which usually are the biggest. In other words, objets that have short lives usually also are small.

    11. Supposedly no, that’s what the GC is there for.

    12. The GC will eventually call Dispose on IDisposable objects. Knowing that there may be quite some time until an object gets GC’ed (see 4), and that many resources are limited, you call Dispose yourself as soon as you’re over with an object. It doesn’t get GC’d when you call Dispose, but it releases its resources.

  12. So how much faster is it really and is it? WCF performance in comparison. [Via: clemensv@microsoft.com

  13. Tess says:

    Awesome answers from all,  I’m really excited to see that so many people answered so fast:)  I’m going to give it a few days to see what more comes in and send my answers out over the weekend, until then, have a great easter weekend

  14. Stefan Wenig says:

    mark: you can use pointers with unsafe, but GC could still clean them up (or move them), so you’d have to pin them first. once pinned, they aren’t going to be collected. however, as long as you use the "fixed" statement, you can be pretty sure that the pin will be released. so i’d still think the answer to be "no".

    btw, i have to correct my answert to 1 again: without hyperthreading, dual core means two logical processors, not four. I guess that was supposed to be the easy part 😉

  15. Petros says:

    1. Two one for each core

    2. I am purely guessing workstation with concurrent GC off.

    3. One.

    4. When the GC feels it is time.

    5. After having survived a GC 0 and 1 collection if it’s not on the LOH.

    6. Probably because the applications has reached a “balanced state” where the long lived data lives in GEN 2 and the short lived data which probably is less only exists in GEN 0.

    7. I am clueless here but I guess 4 heaps with server and 1 with workstation.

    8. I guess yes.

    9. While the process is running? Otherwise I believe it is in the config file.

    10. Implement an empty finalizer or have a strong reference to the object from an object with a finalizer.

    11. You could always block the finalizer thread so my answer has to be yes.

    12. It is not important! At least until you have convinced you boss that some cool new hardware will solve your resource problems 😉

  16. dal says:

    1. 2, 1 per processor

    2.  workstation

    3.  4

    4. When it is no longer rooted, and does not have a finalizer, or its finalizer has run and it has not been resurrected.

    5.  A GC occurs and the object is still rooted, on the finalization queue, or referenced by objects on the finalization queue. All such objects get promoted, either from Gen0->1, or Gen1->2.

    6. Probably because the objects in Gen0 and 1 get collected quickly and go away. Objects in gen 2 are collected infrequently, and objects tend to accumulate here in long running processes.

    7. 4, 1 per processor/GC thread, shows up in private bytes

    8. no. All versions are in same dll.

    9.  yes,but not while running, only before the runtime starts

    concurrent

    <configuration>

     <runtime>

       <gcConcurrent enabled="true" />

     </runtime>

    </configuration

    to run as server

    <configuration>

     <runtime>

       <gcServer enabled="true" />

     </runtime>

    </configuration>

    10.  

    1) If a object has a finalizer and GC.SupressFinalize is not called before the object is no longer rooted and a GC occurs. This could occur is the object is Disposed and GC.SupressFinalize is not called.

    2) If the object is no longer used but is referenced by an object that is still rooted. An example is where a form subscribes to an event (i.e. a multicast delegate) when it is opened and never unsubscribes from that event when it is closed.

    11. *real* memory leak?  

    Yes. Same example as a form that subscribes to an event and never unsubscribes. If the form is repeatedly opened and closed, then each instance will remain in memory even though it is no longer referenced anywhere (other then the delegate).

    12.  Those are essentially connections to unmanaged objects and are not automatically cleaned up. The GC cleans up memory, but that is all. Connections, (database, network, etc.) are not automatically deallocated.

    In some cases it is important to have precise lifetime control; files, network and database connections, etc., have this attribute.

    In addition, some objects have Close semantics (e.g. complex shutdown sequences), which are more involved then simply cleaning up its memory, and which require access to objects that may not be valid in the context of a finalizer. Usually you should not touch another managed object in a finalizer, but you can in a dispose method.

  17. nativecpp says:

    1) 2 or 4 it hyper-threaded

    2) Don’t know

    3) 4

    4) when it is not rooted AND there is a memory pressure

    5) when it is still rooted during GC 0, 1, etc

    6) Besides LOB, gc2 is not as frequently collected as GC 0 & 1. Also GC 2 is free but never compacted

    7) 4

    8) no true. it is true for 1.1

    9) in the config

    10) Finalizer and being referenced by root object

    11) Yes. Your example of ASP.NET Case Study: Tracing your way to Out Of Memory Exceptions.

    12) Because connection is a limited resource and GC does NOT know anything about connection. GC just knows raw data

  18. bhartung says:

    1. How many GC threads do we have in a .NET process running the Server version of the GC on a dual-core machine?

    I suspected the answer was 2 (one per logical processor) under the server GC.  Since you were kind enough to teach us to fish, I went ahead and ran windbg on a server with two dual-core processors, I ran a C# 2.0 console app that simply does a Console.ReadLine (with a gcServer enabled="true" specified in the app config file) and attached to it.  Using the ~k command to inspect the callstack for each native thread, I found 4 thread stacks starting with mscorwks!SVR::gc_heap::gc_thread_stub (the !SVR confirmed I was running in server gc mode…before adding the gcServer element to my app

    config, there was only one gc thread and its stack started with mscorwks!WKS, hence workstation gc mode).  So dividing the outcome by 2 (since again I had 2 dual-core

    processors), I confirmed my suspicion.

    2. What GC mode is used in the web development server (cassini) on a quad proc machine? Why?

    Probably workstation since it’s a Windows Forms app.

    3. How many finalizer threads do we have in a .NET process running the Server version of the GC on a quad proc machine?

    Just one.  The ability to support multiple finalizer threads has been on the future enhancements list for some time now.

    4. When is an object garbage collected?

    When 1) a memory allocation request exceeds the current generation 0 segment capacity (or because of an exlicit call to GC.Collect) and 2) the object is no longer reachable.

    5. What causes an object to move from Generation 0 to Generation 1 or to Generation 2? Each time an object survives a collection, it is promoted to the next generation (unless it is pinned).

    6. If you look at the GC sizes for Generation 0, 1 and 2 in perfmon, why is most of the memory in the process in Gen 2?

    Gen 2 objects are those that have survived the longest.  Objects in the earlier generations are shorter-lived and quickly move to Gen 2 if they survive only 2 collections (which can come fast-and-furious depending on the amount of allocation going on).  Perfmon also doesn’t typically update itself as fast as collections are going on, so you’re seeing essentially a snapshot of "in-flight" objects making their way to Gen 2 or dying trying.

    7. How many heaps will you have at startup on a 4 proc machine running the server GC?  How many would you have if the same machine was running the workstation GC?  Will the memory used for these show up in private bytes or virtual bytes in perfmon or both?

    Assuming you are just talking GC Heaps (and not internal runtime heaps like the loader heap) the answer is 4 for server GC and 1 for workstation.  This is easily determined with the !EEHeap command in windbg with SOS.  Using the !ProcInfo command, it appears as though the memory shows up in both the Private and Virtual bytes.

    8. (Leading question:))  Is the fact that you have mscorwks.dll loaded in the process in 2.0 an indication of that you are running the workstation version of the GC?

    No.  Since 2.0, both flavors of the GC are implemented in mscorwks.dll (you can look for the !SVR and !WKS to tell the difference as described above).

    9. Can you manually switch GC modes for a process?  If so, how and under what circumstances?

    I doubt it, but if it can be done it would almost certainly have to be in a hosting scenario.

    10. Name at least 2 ways to make objects survive GC collections unneccessarily.

    Pin them or implement a finalizer (the latter of which always makes objects survive at least one extra generation as they are placed on the finalizer queue and possibly more if they are resurrected).

    11. Can a .NET application have a *real* memory leak?  In the C++ sense where we allocate a chunk of memory and throw away the handle/pointer to it?

    Sure.  It can easily happen during an Interop scenario.  Some scenarios also smell a lot like leaks such as compiled regular expressions and temporary assemblies created when emitting code (before lightweight codegen existed).

    12. Why is it important to close database connections and dispose of objects? Doesn’t the GC take care of that for me?

    The GC only takes care of the managed portion of the memory.  It doesn’t directly collect native memory or free their resources (although the kernel can reclaim most resources at process exit).

    -Brian Hartung

  19. pmackay@hotmail.com says:

    That are my 2 cents.

    7.- well, discarding low frequency heap and all that internall stuff, 8 heaps, 4 for normal heaps and 4 for LOH

    In a workstation, 2 heaps, the normal and the LOH

    In both counters because one of them is the reserved and the other, the commited memory

    8.- Nope. 2.0 has all the code in that dll.

    9.- Yes, but I tried and didn’t work..at least in iis 5.1.

    10.- have a finalizer (that’s not tru if you call gc.supressfinalizeme) and pinned.

    11.- No. At least in a 100% managed world, no.

    12.- It will take care, but could be too late for your server.

    Patrick.

  20. You’ve been kicked (a good thing) – Trackback from DotNetKicks.com

  21. It was really exciting to see that so many people answered the .NET GC PopQuiz , especially seeing that

  22. says:

    Als Nachtrag zu meinem gestrigen Post In den Tiefen des .NET Frameworks – Der Garbage Collector heute

  23. beny says:

    wat is the size of the managed heap allocated by a preocess at runtime?

  24. I recently was asked to take a look at some VSTO test automation that wasn’t behaving correctly on lab