.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
Anonymous
April 02, 2007
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.Anonymous
April 02, 2007
- 2 threads
- Workstation,
- 4
- Out of scope
- Allocation triggers GC and it causes live objects to promote from 0 to 1 or 1 to 2
- Long lived and big objects(8 kb) promoted to generation 2
- server GC -> 4 heaps and workstation GC -> 1 heap and initially it will be private bytes
- Yes
- For individual process answer is no, but we can set GC mode for machine, it is usually done for Winform application on multicore machines
- 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.
- Yes
- 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.
Anonymous
April 02, 2007
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 onlyAnonymous
April 02, 2007
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.Anonymous
April 02, 2007
Currently interviewing for a .Net PFE position w/ you guys, so I should know all of these, so here goes:
- Two, one per CPU
- 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.
- ?
- You never know for sure, but it's marked for GC when it's reference count equals zero.
- When it "survives" a GC, i.e. it still has references to it when the GC is invoked.
- These are the objects with the most references to them, as well as the "large object heap."
- Guessing... 4. 1. Private bytes.
- No. mscorsvr was folded into mscorwks for the 2.0 release.
- I have no idea. I'm assuming you can via config sections, but the process will need to be restarted.
- Pin them via managed C++? That's the only one I know of.
- Yes (kinda), objects can be orphaned but they won't hang around forever.
- 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.
Anonymous
April 02, 2007
1/ It's dual core, so only 2 3/ 1 10/ Give it an unnecessary finalizerAnonymous
April 02, 2007
The comment has been removedAnonymous
April 02, 2007
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.Anonymous
April 02, 2007
The comment has been removedAnonymous
April 02, 2007
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!Anonymous
April 02, 2007
Interesting questions, and I'd love to get the answer for several of them!
- 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.
- Objects that are still referenced when the GC runs move from gen 0 to gen 1. And so forth.
- 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.
- Supposedly no, that's what the GC is there for.
- 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.
Anonymous
April 02, 2007
So how much faster is it really and is it? WCF performance in comparison. [Via: clemensv@microsoft.com...Anonymous
April 02, 2007
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 weekendAnonymous
April 02, 2007
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 ;-)Anonymous
April 02, 2007
- Two one for each core
- I am purely guessing workstation with concurrent GC off.
- One.
- When the GC feels it is time.
- After having survived a GC 0 and 1 collection if it’s not on the LOH.
- 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.
- I am clueless here but I guess 4 heaps with server and 1 with workstation.
- I guess yes.
- While the process is running? Otherwise I believe it is in the config file.
- Implement an empty finalizer or have a strong reference to the object from an object with a finalizer.
- You could always block the finalizer thread so my answer has to be yes.
- It is not important! At least until you have convinced you boss that some cool new hardware will solve your resource problems ;-)
- Anonymous
April 03, 2007
- 2, 1 per processor
- workstation
- 4
- When it is no longer rooted, and does not have a finalizer, or its finalizer has run and it has not been resurrected.
- 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.
- 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.
- 4, 1 per processor/GC thread, shows up in private bytes
- no. All versions are in same dll.
- 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>
- 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.
- 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.
- 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).
- 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.
- Anonymous
April 04, 2007
- 2 or 4 it hyper-threaded
- Don't know
- 4
- when it is not rooted AND there is a memory pressure
- when it is still rooted during GC 0, 1, etc
- Besides LOB, gc2 is not as frequently collected as GC 0 & 1. Also GC 2 is free but never compacted
- 4
- no true. it is true for 1.1
- in the config
- Finalizer and being referenced by root object
- Yes. Your example of ASP.NET Case Study: Tracing your way to Out Of Memory Exceptions.
- Because connection is a limited resource and GC does NOT know anything about connection. GC just knows raw data
- Anonymous
April 06, 2007
- 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.
- 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.
- 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.
- 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.
- 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).
- 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.
- 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.
- (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).
- 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.
- 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).
- 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).
- 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
Anonymous
April 07, 2007
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.Anonymous
April 10, 2007
Tess proposait il y a quelque temps, un Quiz sur le garbage collector http://blogs.msdn.com/tess/archive/2007/04/02/net-garbage-collection-popquiz.aspxAnonymous
April 12, 2007
You've been kicked (a good thing) - Trackback from DotNetKicks.comAnonymous
April 16, 2007
It was really exciting to see that so many people answered the .NET GC PopQuiz , especially seeing thatAnonymous
May 29, 2007
Als Nachtrag zu meinem gestrigen Post In den Tiefen des .NET Frameworks – Der Garbage Collector heuteAnonymous
September 22, 2007
wat is the size of the managed heap allocated by a preocess at runtime?Anonymous
August 26, 2008
I recently was asked to take a look at some VSTO test automation that wasn't behaving correctly on lab