Search This Blog

Showing posts with label debugging. Show all posts
Showing posts with label debugging. Show all posts

Thursday, July 26, 2012

windbg - issues loading sos for .net framework v4

from stack overflow:
"The CLR runtime dll was renamed to clr.dll with .NET 4. So in order to load the correct version of SOS you need to adjust your .loadby command. I.e.
.loadby sos clr"

Tuesday, April 15, 2008

.NET Garbage Collection PopQuiz Quick Answers

all credit to Tess for this.

the original quiz can be found here

Tess's answers and further explanation can be found here

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

A: server version = one thread per logical processor = two threads (four if hyper threaded)

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)

A: cassini = windows forms app = user interaction = use 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?

A: Tess states that the answer is one per process. further investigation only lead to more confusion - server version of GC on a quad proc machine means four GC threads (eight if hyper threaded). i believe the answer is either one or four/eight. i'll keep reading and update this when i find an explanation that makes sense to me

UPDATE: the gentleman walker looked into this and found that, at a given time, there is one per .NET process with a maximum equal to the sum of the number of worker process allocated to each application pool. the process will only show up in taskman if the associated app pool/web site is in use


4. When is an object garbage collected?

A: when the object is no longer referenced and a GC occurs for the generation your object is in

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

A: the object is still referenced when a GC occurs for the generation the object is in

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?

A: gen 0 and gen 1 have small sizes (though these sizes are not fixed); gen 2 does not. since GC occurs when gen 0 and gen 1 are nearly 'full', referenced objects will eventually end up in gen 2 where they will remain for the remainder of their life (i.e. until they are no longer referenced and eventually cleaned up)

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?

A: one small object heap and one large object heap per logical processor for server GC; one small object heap and one large object heap in workstation GC. as far as the memory part of the question, this is how i understand it - virtual bytes corresponds to memory reserved by a process, whereas private bytes is the memory actually being used by the process. if all goes smoothly, the graphs for these will follow each other which means the process is allocating memory correctly. at startup, virtual bytes may be a lot larger than private because the reserved memory hasn't been used it, but private bytes should eventually catch up to an extent and both should smooth out in perfmon

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?

A: no; in 2.0, both the server and workstation versions of the GC reside in mscorwks.dll

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

A: the answer is "yes, but...". i'll leave Tess to explain the restrictions:

a) you can not run the server version on a single proc box, it will default to workstation

b) you can not run concurrent while also running server

c) if the runtime is hosted, the hosts GC mode will override the configuration


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

A: create an unnecessary finalize method. create a objects within a method and then have the method perform some action for a long time, preferably one that causes memory pressure which will trigger a GC and the referenced objects will not be collected

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?

A: not in the C++ sense, but leaking memory is quite possible. see Tess lab 6 (which was also covered in my presentation)

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

A: disposing the objects releases their resources and makes them available for GC immediately (note: calling dispose on an object does not trigger a GC)

Tuesday, January 29, 2008

preserving the stack trace when handling exceptions

i just now stumbled across something that i didn't realize (though it makes sense) about the difference between throw and throw ex within a try...catch...finally block and i thought i'd share the wealth. i have the feeling this may be one of the "holes" in my coding knowledge/fundamentals that everyone else knows except for me since i was a physics major and only took 16 hours worth of computer science back in college. if so, you can politely skip this post and be happy for me that i learned something valuable. if you think i'm dumb for not knowing this, just know that i think you're dumb for not knowing that an operator that commutes with the Hamiltonian does not evolve with time. yeah, what now??

here's the gist:
case i) if a method call within a try...catch block results in an exception, calling throw(with or without an exception instance) causes any code in the ...finally block to immediately execute and then execution continues on its jolly way up the call stack. if you want to log anything about the error, do so before calling throw. furthermore, calling throw by itself preserves the call stack, whereas calling throw with an exception instance causes the stack trace to restart from the method that re-throws the exception and you lose whatever precious debugging information you had about what was going on before the call.

case ii) if procedural code within a try...catch block results in an exception, you lose the stack trace whether you throw with an exception instance or without. you should log what you need to know about the error before you throw as suggested in case i) and additionally log the stack trace.

if you are truly masochistic/sadistic (not sure which but i'd lean towards the former), you can follow what some bloke by the name of Chris Taylor outlines here

Wednesday, January 23, 2008

thread was being aborted

can it be that this demi-god of t-sql can also code and happens to know a thing or two about debugging? holy shit, how has some beautiful lady not yet scooped him up and made him hers by constantly giving him hot, hot lovin? i ask myself these questions often. i also ask myself who the hell thinks that choking a dude is a good way of saying 'nicely done', but that's a story for another time...

if you are using response.redirect(url) or server.transfer in your web application and receiving a "Thread was being aborted" error despite the fact that your application does absoluetely nothing explicitly with threading, you may be as confused as i was when this happened to me. i'll be the first to admit that, despite all those lovely Microsoft certification letters after my name, i'm far from an expert on page life cycles and the intricacies of what goes on behind the scenes when the application does something as seemingly simple as changing the page that is displayed to a user. here is what i found:

response.redirect and server.transfer both internally call response.end. response.end ends the current page execution, the Application_EndRequest event is fired and a ThreadAbortException is thrown (i'm unsure whether or not resonse.end throws the ThreadAbortException to immediately shift the page life cycle to Application_EndRequest of if the exception is thrown in the Application_EndRequest event). that code which follows response.end (and, therefore, response.redirect and server.transfer) is not executed.

you: "why not just wrap the page redirection in a try...catch block and catch the exception?"

a ThreadAbortException will be rethrown at the end of your catch block whether you like it or not. it will then execute everything in your ...finally block and then kill your current thread. if you feel like dealing with threads, you can call thread.resetabort in your catch block to continue executing your thread, but this discussion assumes you are not dealing with threading, so scratch that.

solution: it turns out this is actually a pretty easy fix. if you are using response.redirect(url), use the overloaded version response.redirect(url, false) instead. if you are using server.transfer, use server.execute.

works cited:
Microsft Help and Support
DotNetJunkies - In the line of Fire -- Shaunak Pandit
Microsoft Visual Studio 2005 Documentation - ThreadAbortClass

Tuesday, January 22, 2008

deadlocks are bad

what is a deadlock? the way i typically explain it is like so (this is simplified but i think it gets the idea across):

  • process A has a lock on table A and is waiting to update it with information from table B
  • process B has a lock on table B and is waiting to update it with information from table A

since neither process will release its lock until the other processes releases its lock, we have ourselves a deadlock. most of the time SQL server "resolves" this issue itself because it has a thread dedicated to its lock manager and someone much smarter than myself came up with an algorithm that allows the lock manager to detect this and kill one of the processes. i have no clue how it chooses which process is the victim of its kill statement, but, from my experience, 99% of the time it is does make this decision and it does kill one of the processes. i've not yet had this happen in SQL 2005, but i can count on one hand the number of times when a deadlock occurred in SQL 2000 and SQL left the decision up to me. in all of these cases, the decision for me was simple - i opened up the SQL activity monitor, scrolled to the right, and saw that a whole bunch of locked processes listed the same process in the 'Blocked By' column. by no means should you be cavalier and just kill this single process before you know what it is, but it's a good place to start. i figured out what the process was and had my client log on to the server hosting the application and simply close it.

back to the other 99% of the time SQL Server resolved the deadlock automagically. this is still very bad. some application was trying to perform some operation on a table or its data and SQL Server flat out squashed it before it could finish. there are certainly ways design a database to minimize the chance of this, but no matter how badass you think your 5NF database is (because there is no way you are badass enough to reach 6NF), you are going to experience a deadlock at some point. i recommend you read the following article to better understand what is going on, and how to track down resolve the problem:

http://support.microsoft.com/kb/832524