Hello everyone,
Two questions about the following code,
1. When instance of Class1 is put to GC queue, its wrapped Obj instance is 100% ensured to move to GC queue, but the order of whether the memory and Finalize method of Class1 instance or obj1 instance will be called first can not be decided (GC may make different decision in different situations)?
2. If some instance does not hold the reference of Class1, but holds the reference to obj1 through public method PassOut, in this situation, Class1 instance is prevent from being GCed?
[Code]
using System;
///
/// Summary description for Class1
///
public class Class1
{
private Component Obj = new Component();
public Component PassOut()
{
return Obj;
}
public Class1()
{
//
// TODO: Add constructor logic here
//
}
}
[/Code]
thanks in advance,
George
George GeorgePosted Apr 22, 2008, 11:27 PM
Thanks Alan,
Question answered. You are so knowledgable and nice. :-)
regards,
George
AlanPosted Apr 22, 2008, 12:10 PM
George GeorgePosted Apr 22, 2008, 3:45 AM
Thanks Alan,
I agree with you in Finalizer we should only deal with releasing of native resource. I have got CLR via C# book, and referred the chapter 20, GC chapter. For the managed resource in Finalizer, it is suggested we only access the ones which do not have Finalizer method, because if there is finalizer method, the GC order of current object and referred object is not decided.
(section "Using Finalization with Managed Resources").
Do you agree or have any comments?
(So, our conclusion is, dealing with unmanaged resource and manged resource without Finalizer?)
regards,
George
AlanPosted Apr 21, 2008, 11:35 AM
In C# you can never access base.Finalize() directly.
However, when you declare a destructor for a class, the compiler automatically inserts a call to base.Finalize() in the last line of the MSIL.
In C#, defining a destructor is (in effect) the same as overriding the Finalize() method which all objects inherit from System.Object.
There's some further advice on what you should and shouldn't do in the destructor here:
http://msdn2.microsoft.com/en-us/library/system.object.finalize.aspx
Although I'm not keen on general rules as situations may arise where you need to do something different, I think the best advice is to confine yourself to only putting a call to the Dispose() method in the destructor thus ensuring that the latter will only do its stuff if it hasn't been called before.
George GeorgePosted Apr 21, 2008, 11:06 AM
Thanks Alan,
1.
From this link,
http://msdn2.microsoft.com/en-us/library/ddae83kx.aspx
Seems that we can only access base.Finalize in Finalizer method of current class? Any comments? Please feel free to correct me if I am wrong. :-)
--------------------
An object's Finalize method should not call a method on any objects other than that of its base class.
--------------------
2.
But actually there are many code samples, which access more than base.Finalize, my question is are there any any rules or recommendations what are safe to access besides base.Finalizer? Any referred links? :-)
regards,
George
AlanPosted Apr 21, 2008, 11:01 AM
It's true that the FileStream() class has a finalizer (in .NET as well as Rotor) but it may be a long time before the FileStream is finalized and in the meantime you won't be able to use the file handle because the operating system will think it's still in use.
You can see this by opening a StreamWriter, writing some stuff to a file and then failing to close it. If you then attempt to open the file shortly afterwards using a StreamReader you'll be informed the file is still in use.
On the other hand, if you fail to clean up managed resources immediately, then all it means is that they occupy memory longer than they should which wouldn't normally prevent you from doing something.
George GeorgePosted Apr 21, 2008, 10:08 AM
Thanks Alan,
StreamWriter wraps FileStream, and FileStream has its Finalizer? So, no resource leak? Any comments?
http://www.123aspx.com/Rotor/RotorSrc.aspx?rot=40741
regards,
George
AlanPosted Apr 21, 2008, 9:56 AM
From .NET 2.0 onwards, neither StreamWriter nor its base classes TextWriter and MarshalByRefObject define a destructor (i.e. A Finalize() method). They will therefore inherit System.Object's Finalize() method which does nothing.
Consequently, unless you call Close() or Dispose() on the StreamWriter object there will definitely be a resource leak as the file handle will not have been released. Also these methods ensure that the file has been properly flushed to disk.
Curiously, StreamWriter did override the Finalize() method in .NET 1.0/1.1 though they must have decided to remove it for some reason.
The StreamWriter class contains both managed (buffer, encoding etc) and unmanaged resources (file handle) but it's the latter which it's particularly important to clean up - if you don't clean up the former now, they will be cleaned up when the GC gets around to finalizing/destroying the corresponding managed objects.
George GeorgePosted Apr 21, 2008, 1:27 AM
Thanks Alan,
1.
One further question, if in my class, there is a StreamWriter data member, in the Finalizer method, if I do not close the StreamWriter, there should not be any resource leak, right? (because the Finalizer of StreamWriter itself will clean up native file handle resource wrapped by StreamWriter?)
2.
So, C# I/O class like StreamWriter is managed resource, not unmanaged resource?
regards,
George
AlanPosted Apr 20, 2008, 1:13 PM
What I'm saying, George, is that if the parent object contains a reference to a child object at the point when the parent object is about to be finalized, then the parent object will be finalized and its memory reclaimed before the child object.
I don't think this is inconsistent with what it says in the article because, early on, it contains this paragraph:
"If the object has references to other objects, the traditional destructor would need to destruct these as well. This is no longer necessary in .NET as the garbage collector will reclaim their instance memory at some point."
'At some point' will be some time after there are no longer any references to those objects (remembering there might be other references) and they can therefore be finalized themselves.
The difficulty you have with non-deterministic finalization is that you don't know precisely when it will occur and what may have happened in the meantime but may need to take account of this when coding your Dispose/Close methods and/or the destructor.
George GeorgePosted Apr 20, 2008, 3:32 AM
Thanks Alan,
Even if there is no external reference to the wrapped object, it will always still be GCed before the owner object (when there is no reference to owner object)?
I doubt it. Here is why I doubt. From some study, my point is the order is non-deterministic. Any comments?
Non-deterministic Finalization
http://dn.codegear.com/article/29365#NonDeterministicFinalization
regards,
George
AlanPosted Apr 19, 2008, 6:55 PM
The garbage collector only destroys one object at a time.
If an object (A) being collected contains a field which refers to another object (B), then the field's memory contains a pointer to where B is stored elsewhere on the heap, not B itself.
When A's memory is reclaimed it will, of course, no longer contain a reference to B but whether B itself then becomes eligible for garbage collection depends on whether there are any other references to it within the application.
In general,therefore, A will always be reclaimed before B and the existence of other references to B won't prevent A from being destroyed.