TextWriter fails on Close() call in destructor

  • Thread starter Thread starter Zytan
  • Start date Start date
Just as I suspected:
Because classes are initialized, but never finalized.

To be clear, you meant:
"Because *static* classes are initialized, but never finalized."

But, why aren't they? I'd like to know the reasons why, although it
is futile, since it doesn't change reality.

In Turbo Pascal, which the C# designer made, you could invoke a clean
up process on exit, which would be invoked in the 'static
constructor', and thus have a 'static destructor'. I know you can do
something like this with the DomainUnload event, and I am assuming is
much the same thing. I fear, though, it doesn't help me, since my
underlying Stream will still be finalized before it ever gets called.
I have not tested this, yet, though.
No. I suggest you just flush your TextWriter after each call, and let
the OS close the handle automatically when the program exits.

I found a hack: Make the class non-static, instantiate an instance
using a private instance c'tor within the static c'tor, thus the
finalizer will run. And I tried this, and still my Stream is
finalized before I get to poke at it. Besides, I hate hacks.

The other 'hack', which is not so much a hack, is to use the
DomainUnload event, which I haven't yet tried.

Zytan
 
I can't believe C# doesn't give me access to dispose of my own objects
What else could it do? You could have two objects with references to
each other, but no other references to them. *One* of them has to be
finalized before the other, doesn't it?

Yes, true.

My point is: Can't it wait to clean my dinner plate until after I am
done eating?

Zytan
 
My point is: Can't it wait to clean my dinner plate until after I am
done eating?

Hm, but if we're both eating off each other's plates, and we are
waiting for each other to stab before we grab the last bite, then
there's a deadlock. I suppose the mother has to step in at this
point.

I don't believe this is the situation I've created, though.

Zytan
 
I can't believe C# doesn't give me access to dispose of my own objects
The reason is that there is no finalizing dependency that tells the
memory management that one object has to be finalized before the other.

Right. My object clean up code is just as likely to be run first as
another object's clean up code. I guess I was naively thinking the GC
knew which object 'owned' which other object, and thus could guarantee
that all of my objects exist until I am done myself.
Because it's calling the finalizers after your main code has finished.
You can't predict when the objects will be finalized, so theoretically
the finalizer may be executed a long time after the main code has finished.
Right.

Why not make an object that works in two states? While the Page class
exists, the file is open, and in the Dispose method of the Page, call
Dispose on the object that will close the log file and change the state
of the object. Any writes to the object after that will be done by
opening the file, write the text and the close the file.

Interesting solution, to open and append to the file if it is already
closed.

When would Dispose be called, though? I just want the logging file to
be open as long as possible.

Zytan
 
Zytan said:
One question: Is it ok for me NOT to call .Close() or .Dispose() on
the StreamWriter or TextWriter, and let the GC do its work when the
application closes? Presumably, this will properly close the file, as
the GC does call the finalizer on both of them, which does the clean
up work?

I wouldn't depend on it, and certainly not when you've got potential
buffer issues. For example, a buffer in StreamWriter might not be
flushed to the underlying stream, and if the underlying stream gets
disposed first, then you lose the last bit of data you wrote. Not good.

If it implements IDisposable, my general rule is: dispose of it.

GC is for memory management, not resource management.
Please note that StreamWriter does have a finalizer:
http://msdn2.microsoft.com/en-us/library/aa328973(VS.71).aspx
StreamWriter.Finalize Method

It most likely makes a best-effort to flush its buffers to the
underlying stream, hoping against hope that the stream hasn't already
been finalized.

Read this too:

http://msdn2.microsoft.com/en-us/library/ms172236(VS.80).aspx

-- Barry
 
Zytan said:
Right. My object clean up code is just as likely to be run first as
another object's clean up code. I guess I was naively thinking the GC
knew which object 'owned' which other object, and thus could guarantee
that all of my objects exist until I am done myself.

It's easy to think of one's own code as special, but the finalizer you
wrote yourself is not treated differently from any other.

There is no way that objects can own each other. They often reference
each other, which would cause a deadlock in the garbage collection if it
would consider the references. A Form object has a reference to a
ControlCollection, which contains a reference to a Control, which has a
reference back to the Form.

Often things doesn't really make sense until you realise that the
alternatives make even less sense. :)
Interesting solution, to open and append to the file if it is already
closed.

When would Dispose be called, though? I just want the logging file to
be open as long as possible.

It doesn't really matter. As long as you have the reference to the
object, it's not garbage collected. You can dispose at the end of the
Main method of your program.
 
Zytan said:
To be clear, you meant:
"Because *static* classes are initialized, but never finalized."

No, I meant classes. Classes themselves are never finalized. Instances
of classes are finalized.
But, why aren't they? I'd like to know the reasons why, although it
is futile, since it doesn't change reality.

It's just not something that makes much sense - it would only be the
equivalent of adding a handler to the AppDomain unloading event, but
would be less deterministic.
In Turbo Pascal, which the C# designer made, you could invoke a clean
up process on exit, which would be invoked in the 'static
constructor', and thus have a 'static destructor'. I know you can do
something like this with the DomainUnload event, and I am assuming is
much the same thing. I fear, though, it doesn't help me, since my
underlying Stream will still be finalized before it ever gets called.
I have not tested this, yet, though.

Don't forget that while Anders designed C#, he didn't design .NET
itself, and as far as I'm aware (and I could well be wrong) there's no
idea of a static finalizer for types in the CLR.
I found a hack: Make the class non-static, instantiate an instance
using a private instance c'tor within the static c'tor, thus the
finalizer will run. And I tried this, and still my Stream is
finalized before I get to poke at it. Besides, I hate hacks.
Indeed.

The other 'hack', which is not so much a hack, is to use the
DomainUnload event, which I haven't yet tried.

I'm not sure whether it's guaranteed that DomainUnload will be
triggered before static members become eligible for garbage collection
- worth checking out.

I still prefer the idea of flushing the TextWriter after each call
though.
 
Zytan said:
Please note that StreamWriter does have a finalizer:
http://msdn2.microsoft.com/en-us/library/aa328973(VS.71).aspx
StreamWriter.Finalize Method

And this page implies that TextWriter also has a finalizer:
http://msdn2.microsoft.com/en-us/library/ms227564.aspx
TextWriter.Dispose Method ()
"Always call Dispose before you release your last reference to the
TextWriter. Otherwise, the resources it is using will not be freed
until the garbage collector calls the TextWriter object's Finalize
method."

Interesting. Using Reflector, I can't find any evidence of a finalizer
on either TextWriter or StreamWriter. It's possible I'm missing
something, but it's also more than possible that MSDN is incorrect.
 
Jon Skeet said:
Interesting. Using Reflector, I can't find any evidence of a finalizer
on either TextWriter or StreamWriter. It's possible I'm missing
something, but it's also more than possible that MSDN is incorrect.

V1.1 StreamWriter had a finalizer, this one has been removed since V2.0.

Willy.
 
One question: Is it ok for me NOT to call .Close() or .Dispose() on
I wouldn't depend on it, and certainly not when you've got potential
buffer issues. For example, a buffer in StreamWriter might not be
flushed to the underlying stream, and if the underlying stream gets
disposed first, then you lose the last bit of data you wrote. Not good.

For my logger, I flush everything immediately after it is written, so
that the log contains all possible information when a crash occurs, in
case the crash shuts down the app before all data can be flushed. So,
I am not worrying about flushing issues.
If it implements IDisposable, my general rule is: dispose of it.

I agree. But this isn't a typical situation. I can't Dispose of my
object since the system has already finalized the underlying stream
that my Dispose method wants to use. It defeats the purpose. I wish
it would wait for me to dispose of my obects, and remove references to
them, before it finalizes them.

Maybe if I had direct access to the stream itself, it would wait? The
problem with wrappers (StreamWriter) is that I am not sure what it's
doing, and if that has any effect. I cannot see why a wrapper would
release a reference to an object when itself has not finalized, yet,
though. Somehow, the Stream just gets finalized.
GC is for memory management, not resource management.
Right.

Read this too:

http://msdn2.microsoft.com/en-us/library/ms172236(VS.80).aspx

Thanks, Barry. This is the relevant part:

"If neither of these solutions can be used (for example, if a
StreamWriter is stored in a static variable and you cannot easily run
code at the end of its lifetime), then calling Flush on the
StreamWriter after its last use or setting the AutoFlush property to
true before its first use should avoid this problem."

Which is what I do.


The only other possible solution is to have my finalizer REOPEN the
file, and do whatever it has to do with it (like writing EOF
terminators for that file type, like "</HTML>"), and then close it.
But, since I have nothing to write on close, all I have to do it
call .Close(). So, it's pointless.

You recommend that I dispose of the object, since the GC is for memory
management, not resources, but, the GC has already stepped in and
handled my resource for me!

Zytan
 
No, I meant classes. Classes themselves are never finalized. Instances
of classes are finalized.

Oh, ok. Right.
It's just not something that makes much sense - it would only be the
equivalent of adding a handler to the AppDomain unloading event, but
would be less deterministic.

I guess I need something to be deterministic. The problem with a
logger is that it is almost a part of the application overhead. Kind
of like how C++ ensures that the input and output streams are
guaranteed to be available, even though the language states that
(otherwise) there's no particular order chosen. But, this forced
stated makes everything work, since it just doesn't make sense to have
the streams initialized after your own code. And they work right
until the end, so destructors can write to the screen. This is what I
need. It looks like using Trace is the only option. Everything else
is a hack. Unfortunately with Trace, it makes it difficult to ALSO
display the log file onscreen at runtime.
Don't forget that while Anders designed C#, he didn't design .NET
itself, and as far as I'm aware (and I could well be wrong) there's no
idea of a static finalizer for types in the CLR.

Ok. And, it was a kind of 'hack' in Turbo Pascal, as well. It was
basically DomainUnload.
I'm not sure whether it's guaranteed that DomainUnload will be
triggered before static members become eligible for garbage collection
- worth checking out.

I really should check this out, yes.
I still prefer the idea of flushing the TextWriter after each call
though.

Me, too. It's good enough, I think for what I need. I'll stick with
this.

As long as... TextWriter / StreamWriter is cleaned up propely without
a call to Close(). Considering the underlying Stream is already
finalized before I get a chance to call Close(), I think all is well.

Zytan
 
It's easy to think of one's own code as special, but the finalizer you
wrote yourself is not treated differently from any other.
yup.

There is no way that objects can own each other. They often reference
each other, which would cause a deadlock in the garbage collection if it
would consider the references. A Form object has a reference to a
ControlCollection, which contains a reference to a Control, which has a
reference back to the Form.

Wow, i see, so this happens far more often than most (I) would
realize.
Often things doesn't really make sense until you realise that the
alternatives make even less sense. :)

I agree, I run into this all the time with programming. And it
catches even the smartest among us.
It doesn't really matter. As long as you have the reference to the
object, it's not garbage collected.

Yes, except in your Finalizer :)
You can dispose at the end of the
Main method of your program.

My issue was that I wanted all my classes to have access to this
logger class, so I didn't want it to be an instance in the Main
method. If just Main used it, then none of these issues I raised
would even exist. I want all logging to occur at the source of the
problem, deep within the classes that know the most about what is
happened (or specifically, what went wrong).

Zytan
 
Zytan said:
Yes, true.

My point is: Can't it wait to clean my dinner plate until after I am
done eating?

The problem is...
You were done eating. (the program was shutting down)
You had left the restaurant , and the bus boy was cleaning up.
Only THEN did you try to take another bite.

Can you really blame the bus boy????....I mean the door was locked
and you had gone home!!

If you really want to continue with this approach (as opposed to another
solution) Then I would Manually force a cleanup before exiting the
program.

static void Main()
{
try
{
Logger.Init(); //
Run Program
}
finally
{
Logger.Cleanup();
}
}

Or something like this

Bill
 
Have you considered opening and closing the file EVERY time you log
something.
I did something like this myself a few years ago.
It performed OK too.

Bill
 
Zytan said:
My issue was that I wanted all my classes to have access to this
logger class, so I didn't want it to be an instance in the Main
method. If just Main used it, then none of these issues I raised
would even exist. I want all logging to occur at the source of the
problem, deep within the classes that know the most about what is
happened (or specifically, what went wrong).

You can create an instance of it in the main method and use a static
method in the class for writing to the file. The static method can
determine if there is an active instance of the class or not, and use it
if it's there.
 
Zytan said:
My issue was that I wanted all my classes to have access to this
logger class, so I didn't want it to be an instance in the Main
method. If just Main used it, then none of these issues I raised
would even exist. I want all logging to occur at the source of the
problem, deep within the classes that know the most about what is
happened (or specifically, what went wrong).

You can create an instance of it in the main method and use a static
method in the class for writing to the file. The static method can
determine if there is an active instance of the class or not, and use it
if it's there.
 
Zytan said:
I agree. But this isn't a typical situation. I can't Dispose of my
object since the system has already finalized the underlying stream
that my Dispose method wants to use.

You need to keep it alive then, until you do dispose of it, by rooting
it somewhere, either in a local variable low down on the call stack, or
in a static field.
Maybe if I had direct access to the stream itself, it would wait? The
problem with wrappers (StreamWriter) is that I am not sure what it's
doing, and if that has any effect.

No. The GC follows the reference from the StreamWriter to the underlying
Stream. If you keep the StreamWriter alive, the underlying Stream is
kept alive.
I cannot see why a wrapper would
release a reference to an object when itself has not finalized, yet,
though. Somehow, the Stream just gets finalized.

If both Stream and StreamWriter are not ultimately kept alive, then they
both need to be finalized. Which one gets finalized first is
non-deterministic.
You recommend that I dispose of the object, since the GC is for memory
management, not resources, but, the GC has already stepped in and
handled my resource for me!

It has, because you haven't kept the objects rooted!

-- Barry
 
You need to keep it alive then, until you do dispose of it, by rooting
it somewhere, either in a local variable low down on the call stack, or
in a static field.

This is what I have:

static class LogFile
{
private static TextWriter m_twSynch;
...
}

Isn't that rooted? How can I 'root' it more deeply?
No. The GC follows the reference from the StreamWriter to the underlying
Stream. If you keep the StreamWriter alive, the underlying Stream is
kept alive.

Ok, that's what I thought.
It has, because you haven't kept the objects rooted!

Please tell me how I can root them! I believe I have been rooting
them, as you've suggested, all along.

Thanks, Barry!

Zytan
 
Have you considered opening and closing the file EVERY time you log
something.
I did something like this myself a few years ago.
It performed OK too.

Bill, I know this could work, since my first log effort was to not
write anything out until the finalizer. And of course, it can open,
write, close, just fine.

Since I could, and want to, catch unhandled exceptions, I could just
delay the write until then, I suppose.

Thanks, Bill.

Zytan
 
Back
Top