views:

277

answers:

3

Does a destructor get called if the app crashes? If it's an unhandled exception I'm guessing it does, but what about more serious errors, or something like a user killing the application process?

And a few more potentially dumb questions:

  • what happens to all the objects in an app when the app exits and all finalizers have been executed - do the objects get garbage collected or are they somehow all "unloaded" with the process or appdomain?
  • is the garbage collector part of each application (runs in the same process) or is it independent?
+2  A: 

I don't even know C#, but based on my experiences with other programming languages I would guess: If an app crashes, that means there's something seriously wrong with it. Incorrect memory handling etc. It would be strange for any programming language to try to execute destructors/deallocators/finalizers/... in such a case. Things would probably just go more wrong ;)

Update: (forgot to try to answer your other questions) again, not C#-specific, but typically there is no guarantee that destructors/deallocators/finalizers/... actually get called. The reason for this is that when a process quits it is much easier and more efficient to simply "zap" the memory block used for the process than to run its destructors etc. to clean up the memory.

I'm not sure how to answer your last question without going into too much technical detail. There are several ways in which garbage collectors can be designed and made to run, the easiest is that garbage collection stops the current process and continues it when it's done, although it is also possible (but more difficult) to have garbage collectors which run concurrently with processes whose memory they are collecting.

You may want to read up on garbage collection theory to better understand all of this. There's actually a whole site about just this topic: www.memorymanagement.org.

Rinzwind
Thx, good answer. But 1 thing doesn't seem right - you say that even if the app exits normally, that some destructors still might not get called... It doesn't seem right to me, since there is no way for the garbage collector or anybody else (but the objects themselves) to know what kind of native resources the managed objects of the application might have used, so it can't handle that. Anyway I'll give it a try, as nobugs sugested, and post the results when i get a little time...
Antonio Nakic Alfirevic
I can't really say for C#, but Objective-C provides an interesting example here. You should compare the documentation for 'dealloc' (which is the destructor when GC is turned off) and 'finalize' (when GC is turned on). For 'dealloc', the docs say very explicitly that there is no guarantee that it will be called and you should not rely on it to for example close a file. For 'finalize', the docs are fuzzier, it seems to suggest you can rely on 'finalize' as a 'backup' to make sure file get closed etc., but I can't find a sentence that explicitly says 'finalize' is guaranteed to be called.
Rinzwind
Here's a link to the documentation for 'dealloc' and 'finalize' in Objective-C. BTW: While simply trying an experiment to see whether these get called in C# is good, you should also take a look at the documentation. If your experiment shows that it gets called, but the docs don't say there's a *guarantee* then this may be changed in future versions or on other platforms, so you'd better not rely on it. The Obj-C doc. link: http://developer.apple.com/mac/library/documentation/Cocoa/Reference/Foundation/Classes/NSObject_Class/Reference/Reference.html#//apple_ref/occ/instm/NSObject/dealloc
Rinzwind
I dug a little bit deeper into the docs for 'finalize' in Objective-C and found this sentence: "Object finalization occurs at most once during the lifetime of an object—when it is collected." Note that they don't say "exactly once" but "at most once", which to me means it could be 1 or 0 times. So at least in Objective-C there's no guarantee that 'finalize' ever gets called. I expect this is the same for most other languages, including C#, since not making the guarantee allows the OS or VM to do faster memory clean up when possible.
Rinzwind
+2  A: 

If killing an application, the application would almost 100% lost the control immediately and there's no chance for it to call the destructor.

xandy
+5  A: 

I would encourage you to try this for yourself. For example:

using System;

class Program {
  static void Main(string[] args) {
    var t = new Test();
    throw new Exception("kaboom");
  }
}
class Test {
  ~Test() { Console.WriteLine("finalizer called"); }
}

Run this at the command prompt so you can see the last gasp. First with the throw statement commented out.

Like any unhandled exception in Windows, the default exception filter that Windows provides invokes the Windows Error Reporting dialog, displayed by WerFault.exe. If you click "Close program", WerFault will use TerminateProcess() to kill the program. That's a quick end, there is no opportunity to run the finalizer thread, as would happen when a program exits normally.

Windows then takes care of cleanup up the shrapnel. It automatically closes any operating system handles your program might have opened but didn't get a chance to close in the finalizer. Files are the trickier problem here, their buffers don't get flushed and you'll easily end up with a partially written file on disk.

Hans Passant
+1. Thx, very informative. I'll definitely give this and a few other ideas a try to see what's going on.
Antonio Nakic Alfirevic