473,396 Members | 1,599 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,396 software developers and data experts.

GC destructor calls

I am wondering if someone could please explain the behaviour observed
in the following example:

class Contained
{
~Contained ()
{
}
}

class Container
{
Contained m_oContained;

public Container ()
{
m_oContained = new Contained ();
}

~Container ()
{
m_oContained = null;
}
}

Now create an instance of Container then immediately set to null so
that the newly created object is due for garbage collection e.g.:

Container l_oTest = new Container();
l_oTest = null;

What I don't understand is this: the Contained destructor is being
called BEFORE the Container destructor. This doesn't make sense to me
as a reference to the Contained object ( namely m_oContained ) still
exists when the Contained destructor is called. Indeed, when the
Container destructor is later called, the watch window reports
m_oContained as still referencing a valid object?!

Thanks in advance
Nov 16 '05 #1
6 999
Mupp,

There are alot to memory management in .net. I assume, by the way you
are
expecting the destructors to work, that you are coming from a C++
background.
If so then here is where you forgett what you know about destructors in C++
since
they work completly different in .NET.

First of all lets have a look at what ~ClassName actually means to .net. If
you have
a class which looks like this

class Foo
{
~Foo ()
{
// ...
}
}

When you compile this, you will actually end up with

class Foo
{
protected override void Finalize ()
{
try
{
//. . .
}
finally
{
base.Finalize();
}
}

So it actually rolls out to a Finalize call. Now what about Finalizers? Well
the only
thing you really need to know about them are

* You don't know IF they will be called on your objects
* You don't know WHEN they will be called on your objects
* You don't know IN WHAT ORDER they will be called on your objects

Sounds great doesn't it? ;) There are a bounch of issues (by design) in the
GC which
is too "blame" for this. You could read
http://www.csharphelp.com/archives2/archive297.html
for more information on how GC works.

So why does your destructors get called in the order they do? Well first of
all it comes
down to the third point in the list - by concidense. What about the
reference you claim to
exsist between the objects? Well it does exist but since the only way you
can get to the
Contained object is through your Container object, and there is no referens
to the latter
object - your Contained object is deemed unreachable thus it is a candidate
for memory
management.

This has been a very short description what is going on and why. I recommend
you read
the above link (and perhaps a few more - search on google) to get an
understanding on
how the GC works.

HTH,

//Andreas

"mupp" <as**********@hotmail.com> skrev i meddelandet
news:65**************************@posting.google.c om...
I am wondering if someone could please explain the behaviour observed
in the following example:

class Contained
{
~Contained ()
{
}
}

class Container
{
Contained m_oContained;

public Container ()
{
m_oContained = new Contained ();
}

~Container ()
{
m_oContained = null;
}
}

Now create an instance of Container then immediately set to null so
that the newly created object is due for garbage collection e.g.:

Container l_oTest = new Container();
l_oTest = null;

What I don't understand is this: the Contained destructor is being
called BEFORE the Container destructor. This doesn't make sense to me
as a reference to the Contained object ( namely m_oContained ) still
exists when the Contained destructor is called. Indeed, when the
Container destructor is later called, the watch window reports
m_oContained as still referencing a valid object?!

Thanks in advance

Nov 16 '05 #2

"mupp" <as**********@hotmail.com> wrote in message
news:65**************************@posting.google.c om...
I am wondering if someone could please explain the behaviour observed
in the following example:
....
What I don't understand is this: the Contained destructor is being
called BEFORE the Container destructor. This doesn't make sense to me
as a reference to the Contained object ( namely m_oContained ) still
exists when the Contained destructor is called. Indeed, when the
Container destructor is later called, the watch window reports
m_oContained as still referencing a valid object?!


Because a finalizer just isn't a destructor.

It's just a very different thing.

Both objects become elegible for collection at the same time, but the order
in which the finalizers run in indeterminate. While the finalizers are
running the objects still reference each other and they are still "valid".
After an object is finalized it still exists, and won't be destroyed until
the next GC, at the very earliest. It is even possible for a
later-finalized object to resurect the finalized object, and make it
reachable again.

David
Nov 16 '05 #3
mupp wrote:
I am wondering if someone could please explain the behaviour observed
in the following example:

class Contained
{
~Contained ()
{
}
}

class Container
{
Contained m_oContained;

public Container ()
{
m_oContained = new Contained ();
}

~Container ()
{
m_oContained = null;
}
}

Now create an instance of Container then immediately set to null so
that the newly created object is due for garbage collection e.g.:

Container l_oTest = new Container();
l_oTest = null;

What I don't understand is this: the Contained destructor is being
called BEFORE the Container destructor. This doesn't make sense to me
as a reference to the Contained object ( namely m_oContained ) still
exists when the Contained destructor is called.
One thing to realize is that even though m_oContained refers to the
Contained object, that reference is not rooted - it's not accessible
anymore, since the object that holds the reference is not accessible
anymore.

Any object which does not have a rooted reference is eligible for
garbage collection and therefore finalization. You have no control over
the order in which the garbage collector collects objects.
Indeed, when the
Container destructor is later called, the watch window reports
m_oContained as still referencing a valid object?!


--
mikeb
Nov 16 '05 #4
Hello

The object becomes elegible for garbage collection when it is not reachable
by application code, i.e. it is not referenced directly or indirectly by any
local variable (variables in the stacks or all threads) or static fields. So
when you set container to null it is not reachable by the application code,
and so is contained. So they both go out of scope at the same time. I will
give you another example

class A {
public B b;
~A() {}
}

class B {
public A a;
~B() {}
}

A a1 = new A();
B b1 = new B();

a1.b = b1;
b1.a = a1;

a1 = null;
b1 = null;

In the above I created a circular reference, A refers to B, and B refers to
A. But the GC will collect both although they both contain reference to each
other, but both are not reachable by application code.

Best regards
Sherif


"mupp" <as**********@hotmail.com> wrote in message
news:65**************************@posting.google.c om...
I am wondering if someone could please explain the behaviour observed
in the following example:

class Contained
{
~Contained ()
{
}
}

class Container
{
Contained m_oContained;

public Container ()
{
m_oContained = new Contained ();
}

~Container ()
{
m_oContained = null;
}
}

Now create an instance of Container then immediately set to null so
that the newly created object is due for garbage collection e.g.:

Container l_oTest = new Container();
l_oTest = null;

What I don't understand is this: the Contained destructor is being
called BEFORE the Container destructor. This doesn't make sense to me
as a reference to the Contained object ( namely m_oContained ) still
exists when the Contained destructor is called. Indeed, when the
Container destructor is later called, the watch window reports
m_oContained as still referencing a valid object?!

Thanks in advance

Nov 16 '05 #5
as**********@hotmail.com (mupp) wrote in message news:<65**************************@posting.google. com>...
I am wondering if someone could please explain the behaviour observed
in the following example:

class Contained
{
~Contained ()
{
}
}

class Container
{
Contained m_oContained;

public Container ()
{
m_oContained = new Contained ();
}

~Container ()
{
m_oContained = null;
}
}

Now create an instance of Container then immediately set to null so
that the newly created object is due for garbage collection e.g.:

Container l_oTest = new Container();
l_oTest = null;

What I don't understand is this: the Contained destructor is being
called BEFORE the Container destructor. This doesn't make sense to me
as a reference to the Contained object ( namely m_oContained ) still
exists when the Contained destructor is called. Indeed, when the
Container destructor is later called, the watch window reports
m_oContained as still referencing a valid object?!

Thanks in advance


Thanks all

I have read about .NET garbage collection, but not in enough detail it
seems. Must've missed the part about an object 'not being reachable
from application code'.

Thanks again

mupp
Nov 16 '05 #6
mupp... Interestingly, it appears that Visual C++ 2005 supports mixing
"destructors" of managed and native types with the same syntax so:

String^ ReadFirstLineFromString(String^ path) {
StreamReader reader(path);
return reader.ReadLine();
}

As I understand it, in the case of a managed type the compiler
automatically
maps the streamreader destructor to IDisposable::Dispose, obviating the
need for "using". If the type lives on the managed "stack", the
destructor is
invoked when the type goes out of scope.

Regards,
Jeff

*** Sent via Developersdex http://www.developersdex.com ***
Don't just participate in USENET...get rewarded for it!
Nov 16 '05 #7

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

52
by: Newsnet Customer | last post by:
Hi, Statement 1: "A dynamically created local object will call it's destructor method when it goes out of scope when a procedure returms" Agree. Statement 2: "A dynamically created object...
23
by: Fabian Müller | last post by:
Hi all, my question is as follows: If have a class X and a class Y derived from X. Constructor of X is X(param1, param2) . Constructor of Y is Y(param1, ..., param4) .
11
by: santosh | last post by:
Hello, I was going through the Marshal Cline's C++ FAQ-Lite. I have a doubt regarding section 33.10. Here he is declaring a pure virtual destructor in the base class. And again defining...
4
by: Joe | last post by:
I am looking for the quintessential blueprint for how a C++ like destructor should be implemented in C#. I see all kinds of articles in print and on the web, but I see lots of discrepencies. For...
13
by: Peter Hemmingsen | last post by:
Hi, I have written a dotnet class that in its constructor consumes a license from a central license pool. In the destructor it free the license again. But since I don't know when the destructor...
35
by: Peter Oliphant | last post by:
I'm programming in VS C++.NET 2005 using cli:/pure syntax. In my code I have a class derived from Form that creates an instance of one of my custom classes via gcnew and stores the pointer in a...
14
by: gurry | last post by:
Suppose there's a class A. There's another class called B which looks like this: class B { private: A a; public : B() { a.~A() } }
5
by: Frederick Gotham | last post by:
If we have a simple class such as follows: #include <string> struct MyStruct { std::string member; MyStruct(unsigned const i) {
23
by: Ben Voigt | last post by:
I have a POD type with a private destructor. There are a whole hierarchy of derived POD types, all meant to be freed using a public member function Destroy in the base class. I get warning C4624....
9
by: rohits123 | last post by:
I have an overload delete operator as below ////////////////////////////////// void operator delete(void* mem,int head_type) { mmHead local_Head = CPRMemory::GetMemoryHead(head_type);...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.