473,400 Members | 2,163 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,400 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 1124
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
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
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:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
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
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,...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

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.