Topic: C++0x Wish list (memorymanagement)


Author: brangdon@cix.co.uk (Dave Harris)
Date: Wed, 26 Jun 2002 16:55:29 GMT
Raw View
glancaster@ntlworld.com (Garry Lancaster) wrote (abridged):
> The simple rule is: don't touch GC pointers in a destructor.
> This was pretty much my first comment on this subject
> (on 28 May, seems like a long time ago now!)

I am still struggling to see what GC'd destructors /should/ be used for.

They shouldn't be used to free externally visible resources, such as file
handles, database locks, window handles etc, because other programs may be
waiting for them to become free.

They can't touch pointers to GC'd objects. They also can't touch pointers
to the stack, because the object might out-live the stack frame. Likewise
static objects - static object have to be destroyed after the program
terminates and before the GC'd objects they point to are collected, so
GC'd destructors cannot touch static objects either.

So that leaves heap-allocated objects. Why should a GC'd object allocate
and then manually delete objects from the non-GC heap? Wouldn't it be
better to use GC for those too?

GC'd destructors are so complex and dangerous, I would hope there is some
really compelling reason to add them to the language. What is it?

  Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
      brangdon@cix.co.uk      |   And close your eyes with holy dread,
                              |  For he on honey dew hath fed
 http://www.bhresearch.co.uk/ |   And drunk the milk of Paradise."

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Garry Lancaster" <glancaster@ntlworld.com>
Date: Thu, 27 Jun 2002 15:55:55 GMT
Raw View
Garry Lancater:
> > The simple rule is: don't touch GC pointers in a destructor.
> > This was pretty much my first comment on this subject
> > (on 28 May, seems like a long time ago now!)

Dave Harris:
> I am still struggling to see what GC'd destructors /should/ be used for.
>
> They shouldn't be used to free externally visible resources, such as file
> handles, database locks, window handles etc, because other programs may be
> waiting for them to become free.

Whether a resource is suitable for control by a GC system
depends on a number of factors:

1. The abundancy of the resource.

2. The number of resource-managing GC objects created by
the program.

3. The aggressiveness of the GC system in use.

4. The difficulty of managing the resource without GC.

5. Likely system-wide competition for the resource.

6. Anything I missed ;-)

These all apply to memory, just as much as to those resources
you mention. In the right circumstances I would have no issue
using a GC system to manage all the kinds of resources you
mention.

> They can't touch pointers to GC'd objects.

Correct.

> They also can't touch pointers to the stack, because the
> object might out-live the stack frame.

Also correct.

> Likewise static objects - static object have to be destroyed after the
program
> terminates and before the GC'd objects they point to are collected, so
> GC'd destructors cannot touch static objects either.

Not really. Once the program is terminated the only user code that
runs is destructors, which cannot/should not access GC pointers,
so the remaining objects, heap and static, can be destroyed in
any order, provided the existing rules governing static destruction
order are adhered to. It makes sense to destroy the GC objects first
so that their destructors are guaranteed safe use of normal raw
pointers to static objects.

> So that leaves heap-allocated objects. Why should a GC'd object allocate
> and then manually delete objects from the non-GC heap? Wouldn't it be
> better to use GC for those too?

Three reasons:

1. Existing code e.g. vector, basic_string.

2. If object A owns object B, it is in some ways simpler for it just to
manage it manually. GC is overkill here.

3. If object A wishes to manipulate object B at destruction time, it is
dangerous to allocate B using the GC system since (excepting
topologically ordered destruction) B may already be deleted when
A's destrutor runs.

> GC'd destructors are so complex and dangerous,

In my opinion they are neither. In comparison to the other
solutions offered they are a paragon of simplicity. Of
course this is a value judgement, but I make it on what I
think are reasonable grounds: by looking at the code the
various systems require the programmer to write.

> I would hope there is some
> really compelling reason to add them to the language. What is it?

Simplicity and consistency with the way objects allocated
in other ways work.

Kind regards

Garry Lancaster
Codemill Ltd
Visit our web site at http://www.codemill.net



---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: pdimov@mmltd.net (Peter Dimov)
Date: Fri, 21 Jun 2002 19:31:17 CST
Raw View
Ryjek <ryjek@cox.net> wrote in message news:<3D121AD6.5010108@cox.net>...
> Peter Dimov wrote:
> > Hyman Rosen <hyrosen@mail.com> wrote in message news:<3D10BC1B.2040601@mail.com>...
> >>Garry Lancaster wrote:
> >>>I think you refer to resurrection here, which has been
> >>>well covered elsewhere. There is no perfect solution.
> >>
> >>Yes there is. Collect the memory, don't run any code.
> >
> > This is a solution to which problem? A perfect collector should
> > reclaim any resources that are no longer in use. This implementation
> > reclaims memory but leaks everything else. Given the current trends,
> > (a) resource leaks are becoming more important than memory leaks, (b)
> > the C++ community as a whole (hopefully) has improved its style to a
> > point where memory leaks are not the problem they once were.
>
> There is no reason why not to collect other things than just memory. You
> can also collect window handles, file pointers and whatever else is
> thrown at you by the system library writers. Let them collect what they
> see appropriate. This shouldn't concern the end-user programmers.

No, "I" cannot collect them since my destructors won't run. The system
has to collect each and every limited resource. It's possible, but I
don't hold my breath.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: pdimov@mmltd.net (Peter Dimov)
Date: 22 Jun 2002 00:35:13 GMT
Raw View
Sjoerd Schreuder <sa_schreuder@wanadoo.nl> wrote in message news:<3D123F8E.38193BAC@wanadoo.nl>...
> Peter Dimov wrote:
> >
> > Hyman Rosen <hyrosen@mail.com> wrote in message news:<3D10BC1B.2040601@mail.com>...
> > > Garry Lancaster wrote:
> > >
> > > > I think you refer to resurrection here, which has been
> > > > well covered elsewhere. There is no perfect solution.
> > >
> > > Yes there is. Collect the memory, don't run any code.
>
> Which has my preference as well.
>
> > This is a solution to which problem? A perfect collector should
> > reclaim any resources that are no longer in use. This implementation
> > reclaims memory but leaks everything else. Given the current trends,
> > (a) resource leaks are becoming more important than memory leaks, (b)
> > the C++ community as a whole (hopefully) has improved its style to a
> > point where memory leaks are not the problem they once were.
>
> In a infinite memory situation, when memory doesn't need to be reclaimed,
> those other resources won't be reclaimed either.

Of course. That's why I asked "which problem does this garbage
collector solve?" Running out of memory? We have physical memory for
the entire 32-bit virtual address space nowadays, and even before that
point, the virtual memory manager did an acceptable job emulating a
GC.

> Or do you want to
> manually invoke the GC any time you run out of file handles,
> window handles, database connections, and who knows which handles are
> hidden somewhere in a 3rd pary library?

What is the alternative? (The alternative of course is to not rely on
the garbage collector but let's ignore this obvious answer and assume
that we do take advantage of the collector.)

> Do you really think that a GC is able to help you in the following program:
> int main()
> {
>   for(int i=0; i < 10000; ++i)
>     (void)new fstream("foo");  // or WindowHandle, or Socket, or ...
> }

No, I don't think that a GC would be able to help in this case. In
fact, it would be the presence of a GC that would tempt people to
write code like this.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: allan_W@my-dejanews.com (Allan W)
Date: Sat, 22 Jun 2002 00:35:49 GMT
Raw View
> > "Ryjek" <ryjek@cox.net> wrote in message news:3D121AD6.5010108@cox.net...
> >>There is no reason why not to collect other things than just memory. You
> >>can also collect window handles, file pointers and whatever else is
> >>thrown at you by the system library writers. Let them collect what they
> >>see appropriate. This shouldn't concern the end-user programmers.
> >>
> >>But do not run asynchronously any code from the GC.

> William E. Kempf wrote:
> > And what about resources the OS doesn't know about?  For instance, database
> > locks.  There has to be a mechanism in the language to define new resources
> > and to manage the lifetime/ownership of these resources.  GC with out
> > finalizers makes this impossible, and that's why GC with out finalizers is a
> > bad idea.

Ryjek <ryjek@cox.net> wrote
> I will argue that database locks are not the best example for the
> usefulness of finalizers :-) My preference would usually be to let the
> lock go away together with the local scope.

With any sort of "lock," it's important to release it asap. So the
RAII concept typically makes these local objects anyway.

    void updateCustomer(std::string CustomerID) {
        dbLock lock(customerDB, CustomerID); // Lock this customer record
        // ... make whatever changes...
    } // End of scope releases lock

But what about Window handles? Typically the Window object holds the
OS "handle" to the window. The GC system might not know anything about
this handle. If the window is garbage collected, will the window handle
be leaked?

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Garry Lancaster" <glancaster@ntlworld.com>
Date: Sat, 22 Jun 2002 00:36:01 GMT
Raw View
Garry Lancaster:
> > Then you seek a more restrictive model than Java, C#
> > or Boehm et al.

Dave Harris:
> Yes. Dare to be different :-)

In this case unfortunately being different means being less
useful.

> > Do you want an object with a dtor to be garbage collectable,
> > but just have the dtor silently ignored. Or would you not
> > allow an objects with a dtor to be garbage collectable?
>
> The former. My current feeling is to allow destructors but the garbage
> collector would not invoke them.

Does this proposed destructor skipping behaviour
apply to reference-counted GC smart pointers such
as boost::shared_ptr or, as I suspect, are you using a
narrower definition of GC? If I suspect correctly, how
will you explain and justify the difference in behaviour
between the two GC systems e.g. to someone learning
the language?

> This is partly to reflect the current language semantics. Currently
> objects may "leak" even if they have destructors, and their destructors
> are not run.

Let's not standardise leaks. Stick with the boring
but well-known programming technique of calling
object destructors so that we actually release any
resources that we acquired.

> It is also partly to allow objects which can be used either
> with, or without GC. If that is practical.

What you are proposing will have the opposite
effect. The best way to ensure objects can be used
with GC and non-GC allocators is to make the
behaviour with both as similar as possible. Always
calling the destructor is part of this.

Dave Harris:
>>> In my view, finalisers complicate the model more
>>> than they are worth, because of the resurrection problem.
>>> And destructors are even worse, because they make for
>>> undefined behaviour.

> > Why do you think running a destructor leads to
> > undefined behaviour?
>
> Using an object as anything other than raw bytes, after it has been
> destructed, is undefined behaviour. I'm sure you know this so I won't look
> for citations.
>
> Resurrection - that is, an object creating a reference to itself after
> being marked for reclamation - is only a problem if that reference is
> actually used. If we are/worried about this, then finalisation is safer.
> Using an object after it has been finalised is well-defined. Using it
> after it has been destructed is undefined.

You are assuming the programmer gets it right
when dealing with the complexities of finalisation
(where resurrection is legal), but gets it wrong when
dealing with the complexities of destruction (where
it is not). This is not a fair comparison. In both cases
the opportunities for undefined behaviour are present
and in both cases it requires programmer error to take
them. This is the usual situation in C++. So saying
that "destructors...make for undefined behaviour" is
no truer than saying for-loops make for undefined
behaviour and equally information-free.

Kind regards

Garry Lancaster
Codemill Ltd
Visit our web site at http://www.codemill.net

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Hyman Rosen <hyrosen@mail.com>
Date: 24 Jun 2002 02:30:15 GMT
Raw View
Peter Dimov wrote:
> No, "I" cannot collect them since my destructors won't run. The system
> has to collect each and every limited resource. It's possible, but I
> don't hold my breath.

As I posted in another message, the solution is to have finalizers which
are separate from the object being finalized, and which know the resource
to free. Something like this -

struct CloseFileDescriptor : public GC_finalizer
{
 int fd;
 CloseFileDescriptor(int fd) : fd(fd) { }
 void operator()() { close(fd); }
};

struct UsesFileDescriptor
{
 int fd;
 UsesFileDescriptor(char *file) : fd(open(file))
 {
  GC_add_finalizer(this, new CloseFileDescriptor(fd));
 }
private:
 ~UsesFileDescriptor() { }
};
int main()
{
 new UsesFileDescriptor("joe.txt");
 GC_collect();
}

The key is that the finalizer objects are reachable, so they do not
cause any of the revivifiaction problems that have been discussed.
The finalizers themselves become owned by the collector, which will
deallocate them when they are no longer needed. They cannot hold
pointers to the object they are finalizing, because then the objects
will never be finalized, but they can hold copies or pointers to
resources that need freeing.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: brangdon@cix.co.uk (Dave Harris)
Date: 24 Jun 2002 02:30:21 GMT
Raw View
glancaster@ntlworld.com (Garry Lancaster) wrote (abridged):
> In this case unfortunately being different means being less useful.

Can you give an example of what finalisers/destructors would be used for?
The examples I have seen so far have been very dubious, in my view.


> Does this proposed destructor skipping behaviour
> apply to reference-counted GC smart pointers such
> as boost::shared_ptr or, as I suspect, are you using a
> narrower definition of GC? If I suspect correctly, how
> will you explain and justify the difference in behaviour
> between the two GC systems e.g. to someone learning
> the language?

In the reference-counting case, we destroy the object. The smart pointers
keep track of the object so as to be able to destroy it before it becomes
unreachable. In the GC case, we don't destroy the object. Nobody destroys
it. The garbage collector gives the illusion of infinite memory.


[The above is arguing against either finalisers or destructors. Below I am
arguing that if we must run user code on unreachable objects, it should be
finalisers rather than destructors. I'm fighting a retreating battle
here.]


> > Using an object after it has been finalised is well-defined. Using it
> > after it has been destructed is undefined.
>
> You are assuming the programmer gets it right
> when dealing with the complexities of finalisation
> (where resurrection is legal), but gets it wrong when
> dealing with the complexities of destruction (where
> it is not).

"Resurrection" usually means something creating a reachable reference to
an object which was hither-to unreachable. That isn't the problem here.
The problem is loops. A contains a pointer to B and B contains a pointer
to A. Both become unreachable at the same time.

If we destroy A, then B has a dangling pointer. If B uses it there will be
undefined behaviour. If we merely finalise A, then B has a pointer it can
still use while /it/ is being finalised. The programmer can put code into
A, or B, to detect what has happened and deal with it. It's not that the
programmer is smarter, it's that finalisation provides more facilities for
dealing with the problem.

I am not sure what getting it right can mean for destruction case, other
than to avoid such loops in the first place. In which case, I'd just as
soon stick with reference-counting and not change the language.

  Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
      brangdon@cix.co.uk      |   And close your eyes with holy dread,
                              |  For he on honey dew hath fed
 http://www.bhresearch.co.uk/ |   And drunk the milk of Paradise."

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Garry Lancaster" <glancaster@ntlworld.com>
Date: Mon, 24 Jun 2002 10:19:58 CST
Raw View
Dave Harris:
> I am not sure what getting it right can mean for destruction
> case, other than to avoid such loops in the first place.

The simple rule is: don't touch GC pointers in a destructor.
This was pretty much my first comment on this subject
(on 28 May, seems like a long time ago now!)

Kind regards

Garry Lancaster
Codemill Ltd
Visit our web site at http://www.codemill.net

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Ryjek <ryjek@cox.net>
Date: Mon, 24 Jun 2002 15:48:20 GMT
Raw View
Allan W wrote:
> But what about Window handles? Typically the Window object holds the
> OS "handle" to the window. The GC system might not know anything about
> this handle. If the window is garbage collected, will the window handle
> be leaked?

Good question. With window handles the situation is even more complex
because they are most often structured in a tree. Typically, when you
destroy a window handle, handles to all children of the destroyed window
are invalidated. As a result, in the presence of a mirror structure of
C++ objects (again, typical in GUI toolkits), you can potentially be
exposed to dangling handles in finalizers. Note that even with explicit
memory management usually an extra explicit creation/destruction step is
required in such cases.

Many GUI libraries will also keep references to C++ objects (passed
later to event handler callbacks). This will prevent the memory from
being collected at all.

And the last issue is what is the point of closing a window handle in a
finalizer. Is the window supposed to be hanging around on the screen
until the GC kicks in ?

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: John Nagle <nagle@animats.com>
Date: Mon, 24 Jun 2002 17:17:12 GMT
Raw View
Dave Harris wrote:

 > Given that it has finalisation, the underlying GC system seems pretty
 > good. It has methods like SuppressFinalize(),
 > ReRegisterForFinalize(), WaitForPendingFinalizers(), Dispose(), a
 > special interface for disposable objects, two kinds of weak
 > pointer, as well as Finalize() itself. I am sure all this
 > complexity is needed. If we want finalisation, we could do worse
 > than copy Microsoft's core system.

     If we need all that stuff, we're doing something
terribly wrong.  Just because it has many features
doesn't mean it's a good design.

     Microsoft chose not to make a strong distinction
between destructors and finalizers.  That led them
down the path of a very complicated finalization
system.  But it's worth looking at, if only to see
what mistakes to avoid.


     John Nagle
     Animats

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: John Nagle <nagle@animats.com>
Date: Thu, 20 Jun 2002 17:31:51 GMT
Raw View
Garry Lancaster wrote:


> I think you refer to resurrection here, which has been
> well covered elsewhere. There is no perfect solution.
> At the moment I favour making resurrection an error
> with no diagnostic required.


     Don't do that.  At least, don't let resurrection
result in a dangling pointer.  A GC system that
can create dangling pointers, even through programmer
action, is fundamentally defective.

    John Nagle
    Animats

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: brangdon@cix.co.uk (Dave Harris)
Date: Thu, 20 Jun 2002 17:31:54 GMT
Raw View
glancaster@ntlworld.com (Garry Lancaster) wrote (abridged):
> Then you seek a more restrictive model than Java, C#
> or Boehm et al.

Yes. Dare to be different :-)


> Do you want an object with a dtor to be garbage collectable,
> but just have the dtor silently ignored. Or would you not
> allow an objects with a dtor to be garbage collectable?

The former. My current feeling is to allow destructors but the garbage
collector would not invoke them.

This is partly to reflect the current language semantics. Currently
objects may "leak" even if they have destructors, and their destructors
are not run. It is also partly to allow objects which can be used either
with, or without GC. If that is practical.


> Why do you think running a destructor leads to
> undefined behaviour?

Using an object as anything other than raw bytes, after it has been
destructed, is undefined behaviour. I'm sure you know this so I won't look
for citations.

Resurrection - that is, an object creating a reference to itself after
being marked for reclamation - is only a problem if that reference is
actually used. If we are/worried about this, then finalisation is safer.
Using an object after it has been finalised is well-defined. Using it
after it has been destructed is undefined.

  Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
      brangdon@cix.co.uk      |   And close your eyes with holy dread,
                              |  For he on honey dew hath fed
 http://www.bhresearch.co.uk/ |   And drunk the milk of Paradise."

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: pdimov@mmltd.net (Peter Dimov)
Date: Thu, 20 Jun 2002 17:42:19 GMT
Raw View
Hyman Rosen <hyrosen@mail.com> wrote in message news:<3D10BC1B.2040601@mail.com>...
> Garry Lancaster wrote:
>
> > I think you refer to resurrection here, which has been
> > well covered elsewhere. There is no perfect solution.
>
> Yes there is. Collect the memory, don't run any code.

This is a solution to which problem? A perfect collector should
reclaim any resources that are no longer in use. This implementation
reclaims memory but leaks everything else. Given the current trends,
(a) resource leaks are becoming more important than memory leaks, (b)
the C++ community as a whole (hopefully) has improved its style to a
point where memory leaks are not the problem they once were.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Ryjek <ryjek@cox.net>
Date: Thu, 20 Jun 2002 19:12:23 GMT
Raw View
Peter Dimov wrote:
> Hyman Rosen <hyrosen@mail.com> wrote in message news:<3D10BC1B.2040601@mail.com>...
>>Garry Lancaster wrote:
>>>I think you refer to resurrection here, which has been
>>>well covered elsewhere. There is no perfect solution.
>>
>>Yes there is. Collect the memory, don't run any code.
>
> This is a solution to which problem? A perfect collector should
> reclaim any resources that are no longer in use. This implementation
> reclaims memory but leaks everything else. Given the current trends,
> (a) resource leaks are becoming more important than memory leaks, (b)
> the C++ community as a whole (hopefully) has improved its style to a
> point where memory leaks are not the problem they once were.

There is no reason why not to collect other things than just memory. You
can also collect window handles, file pointers and whatever else is
thrown at you by the system library writers. Let them collect what they
see appropriate. This shouldn't concern the end-user programmers.

But do not run asynchronously any code from the GC.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "William E. Kempf" <williamkempf@hotmail.com>
Date: Thu, 20 Jun 2002 21:28:39 GMT
Raw View
"Ryjek" <ryjek@cox.net> wrote in message news:3D121AD6.5010108@cox.net...
> Peter Dimov wrote:
> > Hyman Rosen <hyrosen@mail.com> wrote in message
news:<3D10BC1B.2040601@mail.com>...
> >>Garry Lancaster wrote:
> >>>I think you refer to resurrection here, which has been
> >>>well covered elsewhere. There is no perfect solution.
> >>
> >>Yes there is. Collect the memory, don't run any code.
> >
> > This is a solution to which problem? A perfect collector should
> > reclaim any resources that are no longer in use. This implementation
> > reclaims memory but leaks everything else. Given the current trends,
> > (a) resource leaks are becoming more important than memory leaks, (b)
> > the C++ community as a whole (hopefully) has improved its style to a
> > point where memory leaks are not the problem they once were.
>
> There is no reason why not to collect other things than just memory. You
> can also collect window handles, file pointers and whatever else is
> thrown at you by the system library writers. Let them collect what they
> see appropriate. This shouldn't concern the end-user programmers.
>
> But do not run asynchronously any code from the GC.

And what about resources the OS doesn't know about?  For instance, database
locks.  There has to be a mechanism in the language to define new resources
and to manage the lifetime/ownership of these resources.  GC with out
finalizers makes this impossible, and that's why GC with out finalizers is a
bad idea.

If the problem people are envisioning is that finalizers can be run from a
seperate thread and this asynchrous aspect can cause bugs such as deadlock,
I must point out that we have this issue TODAY.  Ref-counted solutions can
result in the same thing.  If the GC always collects in its own thread (this
isn't a requirement of GC) then this problem becomes more common, but
there's solutions you can employ.  I don't think I agree with this fear.

I do agree, however, that the finalizer and destructor may need to be
seperate concepts, even though conceptually they do the same thing.  The
issue of resurrection, however, is the crux of why we may need seperate
concepts here.

Bill Kempf

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Sjoerd Schreuder <sa_schreuder@wanadoo.nl>
Date: Thu, 20 Jun 2002 21:47:24 GMT
Raw View
Peter Dimov wrote:
>
> Hyman Rosen <hyrosen@mail.com> wrote in message news:<3D10BC1B.2040601@mail.com>...
> > Garry Lancaster wrote:
> >
> > > I think you refer to resurrection here, which has been
> > > well covered elsewhere. There is no perfect solution.
> >
> > Yes there is. Collect the memory, don't run any code.

Which has my preference as well.

> This is a solution to which problem? A perfect collector should
> reclaim any resources that are no longer in use. This implementation
> reclaims memory but leaks everything else. Given the current trends,
> (a) resource leaks are becoming more important than memory leaks, (b)
> the C++ community as a whole (hopefully) has improved its style to a
> point where memory leaks are not the problem they once were.

In a infinite memory situation, when memory doesn't need to be reclaimed,
those other resources won't be reclaimed either. Or do you want to
manually invoke the GC any time you run out of file handles,
window handles, database connections, and who knows which handles are
hidden somewhere in a 3rd pary library?

Do you really think that a GC is able to help you in the following program:
int main()
{
  for(int i=0; i < 10000; ++i)
    (void)new fstream("foo");  // or WindowHandle, or Socket, or ...
}

In my opinion, a GC is a way to emulate infinite memory.

Sjoerd Schreuder

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Ryjek <ryjek@cox.net>
Date: Fri, 21 Jun 2002 05:05:31 GMT
Raw View
William E. Kempf wrote:
> "Ryjek" <ryjek@cox.net> wrote in message news:3D121AD6.5010108@cox.net...

>>There is no reason why not to collect other things than just memory. You
>>can also collect window handles, file pointers and whatever else is
>>thrown at you by the system library writers. Let them collect what they
>>see appropriate. This shouldn't concern the end-user programmers.
>>
>>But do not run asynchronously any code from the GC.
>>
> And what about resources the OS doesn't know about?  For instance, database
> locks.  There has to be a mechanism in the language to define new resources
> and to manage the lifetime/ownership of these resources.  GC with out
> finalizers makes this impossible, and that's why GC with out finalizers is a
> bad idea.

I will argue that database locks are not the best example for the
usefulness of finalizers :-) My preference would usually be to let the
lock go away together with the local scope.

> If the problem people are envisioning is that finalizers can be run from a
> seperate thread and this asynchrous aspect can cause bugs such as deadlock,
> I must point out that we have this issue TODAY.  Ref-counted solutions can
> result in the same thing.  If the GC always collects in its own thread (this
> isn't a requirement of GC) then this problem becomes more common, but
> there's solutions you can employ.  I don't think I agree with this fear.

What I do not like about finalizers is that they break the otherwise
clean execution model and make programs difficult to reason about. I
would accept finalizers if they had no side effects, but this is against
their whole purpose ...

> I do agree, however, that the finalizer and destructor may need to be
> seperate concepts, even though conceptually they do the same thing.  The
> issue of resurrection, however, is the crux of why we may need seperate
> concepts here.

Do you mean that you would like to allow resurrection in finalizers ?
This would be a performance hit for the GC because the whole
reachability analysis would have to be repeated after collection (and
finalization) of each single object.

As others have mentioned, destructors cannot be invoked safely for
garbage-collected objects because in the presence of circular references
they can lead to deleting of already collected objects. So finalization,
separate from destruction is the only viable option.


>
> Bill Kempf
>
> ---
> [ comp.std.c++ is moderated.  To submit articles, try just posting with ]
> [ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
> [              --- Please see the FAQ before posting. ---               ]
> [ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]
>
>

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Hillel Y. Sims" <usenet@phatbasset.com>
Date: Tue, 18 Jun 2002 03:43:40 GMT
Raw View
This is probably the most important point of all to keep in mind w/r/t
garbage collection (applicability and implementation)!

"Dave Harris" <brangdon@cix.co.uk> wrote in message
news:memo.20020615204807.36107B@brangdon.madasafish.com...
> In general, garbage collection doesn't absolve us from needing to do
> object life-time analysis.
>

thanks,
hys

--
Hillel Y. Sims
hsims AT factset.com

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Garry Lancaster" <glancaster@ntlworld.com>
Date: Tue, 18 Jun 2002 16:45:16 GMT
Raw View
Hyman Rosen:
>>> No. Leaks occur (in the C or C++ sense) when there exist no
>>> pointers to allocated memory, and more generally, when this
>>> can happen an arbitrary number of times during the run of the
>>> program.

Garry Lancaster wrote:
> > I think you are attempting to define "memory leak", not
> > "leak", which is more general because it covers any
> > resource.

Hyman Rosen:
> No.

(I reinstated the comment to which I was replying.
You specifically mentioned "allocated memory" and
no other resource. Please try to read what you actually
wrote rather than what you meant to write ;-)

[snip]

> > In general, no, this is not perfectly legitimate. In general
> > it is a leak. A bug. The reason being that there is nothing
> > in the C++ standard that guarantees it (and all resources
> > it owns) *will* simply "go away at program termination".
>
> I refer you to 1.9/6. The standard also doesn't guarantee
> anything about resources even if you do run destructors.
> The only behavior the standard guarantees is access to
> volatile objects and I/O.

In practice, an implementation that did not maintain
the observable behaviour of calls outside the program,
for example to the OS or to dynamically linked libraries,
(and the standard doesn't restrict its definition of I/O to
standard I/O calls) would not be worth using. I am not
aware of any implementation that does not do so. So,
while you are right that strictly it is a quality of implementation
matter, in practice if your code (e.g. destructor code) calls
cleanup operations they will be run.

This is a rather different case from a program that does
not call the cleanup operations and just expects the
implementation to call them on its behalf. This usually
works for memory at the time of program termination, but
for any resource that can be shared between processes,
automatic cleanup would not be a safe strategy for an
implementation to pursue even if it were possible.

[snip]

> I also refer you to 3.8/1 where the standard explicitly
> blesses the notion of ending the lifetime of an object
> by reusing its memory instead of releasing it.

3.8/1 says:
"The lifetime of an object of type T ends when:
- if T is a class type with a non-trivial destructor (12.4), the
destructor call starts, or
- the storage which the object occupies is reused or released."

So, the lifetime of classes with non-trivial dtors ends
when their destructors start. This provides no basis
for thinking you can currently skip the observable
behaviour of the destructors.

> > If there is no difference in observable behaviour between
> > program termination with or without the destructor call then
> > the compiler can elide the destructor call.
>
> This is charmingly naive. I am supposed to deliberately
> initiate a lengthy and useless operation, and the compiler
> is supposed to notice that it's useless and not do it?

If you wish to write portable code there may be occassions
when you are releasing resources at program termination
that the OS/runtime library would release automatically
(especially memory), in which case the compiler is free to
optimize your explicit releases out.

If you do not write portable code you can make
more assumptions based solely on your platform.

> When I can simply not do it to begin with?

Not if you wish to write maximally portable code.

> > Your example is illuminating. You are assuming that
> > destroying a tree node leads to the tree adjusting its
> > internal pointers.
>
> I am assuming a complicated and cross-linked structure,
> so that when objects start being destroyed, they remove
> themselves from maps, and that happens one-at-a-time,
> and those maps rebelance themselves because of it.
> This has nothing at all to do with GC.

In that case, it is rather out of context in a discussion of
GC! The fact remains that data structure nodes that are
managed using GC may have simpler destructors than
their non-GC equivalents because they have an important
extra piece of information: they know that they can only be
destroyed when they are not reachable. This contrasts
with a non-GC data structure where the dead node may
still be pointed to by another reachable node.

> > Are you suggesting a GC that *never* calls finalizers/
> > destructors or just one that skips them for objects
> > remaining at program termination?
>
> Never.

Then you seek a more restrictive model than Java, C#
or Boehm et al.

Do you want an object with a dtor to be garbage collectable,
but just have the dtor silently ignored. Or would you not
allow an objects with a dtor to be garbage collectable?

Kind regards

Garry Lancaster
Codemill Ltd
Visit our web site at http://www.codemill.net

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Hyman Rosen <hyrosen@mail.com>
Date: Tue, 18 Jun 2002 17:49:31 GMT
Raw View
Garry Lancaster wrote:
> 3.8/1 says:
> "The lifetime of an object of type T ends when:
> - if T is a class type with a non-trivial destructor (12.4), the
> destructor call starts, or
> - the storage which the object occupies is reused or released."
>
> So, the lifetime of classes with non-trivial dtors ends
> when their destructors start. This provides no basis
> for thinking you can currently skip the observable
> behaviour of the destructors.

Please read what you are quoting.
     the storage which the object occupies is reused or released.
---------------------------------------------^^^^^^------------

This is perfectly legal:

struct X { X() { cout<<"c"; } ~X() { cout<<"d"; } };
int main()
{
 X *p = new X;
 new(p)X;
 delete p;
}

and will result in "ccd".

> If you do not write portable code you can make
> more assumptions based solely on your platform.
>>When I can simply not do it to begin with?
> Not if you wish to write maximally portable code.

Every single platform of interest to me reclaims
the memory a program has used when the program
exits. I suspect this is also the case for the
vast majority of C++ programmers. I further suspect
that if this was an issue on some platform, the
runtime library would be written to free alloacted
storage on exit whether or not you asked for it.

Not freeing huge data structires on exit is a
well-known design principle, whether or not
you like it.

> The fact remains that data structure nodes that are
> managed using GC may have simpler destructors than
> their non-GC equivalents because they have an important
> extra piece of information: they know that they can only be
> destroyed when they are not reachable. This contrasts
> with a non-GC data structure where the dead node may
> still be pointed to by another reachable node.

They are not reachable from pointers which form the
base of GC, but they are certainly reachable from
each other. If that were not the case, we could just
use reference counting. If the GC system starts
executing user code on objects it's going to collect,
then the unreachability is a lie.

> Do you want an object with a dtor to be garbage collectable,
> but just have the dtor silently ignored. Or would you not
> allow an objects with a dtor to be garbage collectable?

Silently ignored, just as in my example code above.
In the words of the standard, a collected object is
never released, only reused.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Garry Lancaster" <glancaster@ntlworld.com>
Date: Wed, 19 Jun 2002 10:10:15 CST
Raw View
> Garry Lancaster wrote:
> > 3.8/1 says:
> > "The lifetime of an object of type T ends when:
> > - if T is a class type with a non-trivial destructor (12.4), the
> > destructor call starts, or
> > - the storage which the object occupies is reused or released."
> >
> > So, the lifetime of classes with non-trivial dtors ends
> > when their destructors start. This provides no basis
> > for thinking you can currently skip the observable
> > behaviour of the destructors.

Hyman Rosen:
> Please read what you are quoting.

I have.

>      the storage which the object occupies is reused or released.
> ---------------------------------------------^^^^^^------------

I believe that sentence doesn't apply to classes with
non-trivial destructors. They are covered solely by the
first option. But I can see it is a bit ambiguous: that "or"
should probably be an "otherwise".

> This is perfectly legal:
>
> struct X { X() { cout<<"c"; } ~X() { cout<<"d"; } };
> int main()
> {
> X *p = new X;
> new(p)X;
> delete p;
> }
>
> and will result in "ccd".

You've *explicitly* called a constructor on an already
constructed object. This works for the simple X type,
but in general it is bad practice: think what would
happen for example if the constructor acquired a
resource and the destructor released it. (Placement
new is usually called on allocated memory that has not
yet had an object constructed into it.)

> > If you do not write portable code you can make
> > more assumptions based solely on your platform.
> >>When I can simply not do it to begin with?
> > Not if you wish to write maximally portable code.
>
> Every single platform of interest to me reclaims
> the memory a program has used when the program
> exits. I suspect this is also the case for the
> vast majority of C++ programmers. I further suspect
> that if this was an issue on some platform, the
> runtime library would be written to free alloacted
> storage on exit whether or not you asked for it.

In my experience also memory is always freed
at program termination, but I wouldn't guarantee
it in all cases, when the standard offers no
guarantee. And there is a lot more than just memory
to be considered: other resources and non-resource-
related destructor side-effects.

> Not freeing huge data structires on exit is a
> well-known design principle, whether or not
> you like it.

It's an OK optimization sometimes, although not
one I have ever had cause to use. The question is:
is it generally applicable to all classes? And the
answer is no. We have no guarantee that even
memory will be automatically released, we certainly
can have no reasonable expectation that other
resources would be released, and some destructors
have side-effects that go beyond pure resource
release that we would not want to skip.

> > The fact remains that data structure nodes that are
> > managed using GC may have simpler destructors than
> > their non-GC equivalents because they have an important
> > extra piece of information: they know that they can only be
> > destroyed when they are not reachable. This contrasts
> > with a non-GC data structure where the dead node may
> > still be pointed to by another reachable node.
>
> They are not reachable from pointers which form the
> base of GC, but they are certainly reachable from
> each other.

"Reachable" is a GC term with a well-known meaning:
in summary it means reachable directly or indirectly from
a root pointer (one in a register, on the stack, in global
storage and, perhaps, in non-GC heap storage). See

http://www.iecc.com/gclist/GC-algorithms.html#Jargon

The fact that nodes may point to each other is irrelevant.
As long as they are not reachable there is no need to
manipulate pointer values during destruction in order
to maintain the correctness of the data structure.

> If that were not the case, we could just
> use reference counting. If the GC system starts
> executing user code on objects it's going to collect,
> then the unreachability is a lie.

I think you refer to resurrection here, which has been
well covered elsewhere. There is no perfect solution.
At the moment I favour making resurrection an error
with no diagnostic required. Even in languages like
C# and Java that bless it, it isn't very common. The
mere act of calling user code on objects being collected
isn't sufficient to cause resurrection, but it is necessary.

> > Do you want an object with a dtor to be garbage collectable,
> > but just have the dtor silently ignored. Or would you not
> > allow an objects with a dtor to be garbage collectable?
>
> Silently ignored, just as in my example code above.

No, the example code showed an explicit call of the
constructor on an already constructed object. No
destructor call was skipped. In other words the lifetime
of the object was:

allocation
construction
explicit construction
destruction
deallocation

What you are proposing for GC is, if I understand
you correctly, actually:

allocation
construction
deallocation (on most platforms)

Now, we can create an example today that actually does
that:

int main()
{
    foo* p = new foo;
    // Wot no delete?
}

but any number of questionable examples still will not
prove it is a good idea generally.

> In the words of the standard, a collected object is
> never released, only reused.

These are not the words of the standard.

Kind regards

Garry Lancaster
Codemill Ltd
Visit our web site at http://www.codemill.net

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Hyman Rosen <hyrosen@mail.com>
Date: Wed, 19 Jun 2002 12:31:18 CST
Raw View
Garry Lancaster wrote:
> I believe that sentence doesn't apply to classes with
> non-trivial destructors.

You are wrong. Please see 3.8/4.

> You've *explicitly* called a constructor on an already
> constructed object. This works for the simple X type,
> but in general it is bad practice: think what would
> happen for example if the constructor acquired a
> resource and the destructor released it.

I don't see what bad practice has to do with anything.
I am simply pointing out that it is perfectly fine with
the C++ standard to reuse an object's memory without
ever calling its destructor, so it would not be any
violation of the rules for a grabage collector to do
the same.

> some destructors have side-effects that go beyond
 > pure resource release that we would not want to skip.

Then you need to arrange for the cleanup to happen
yourself, not rely on a garbage collector to do it
for you.

> The fact that nodes may point to each other is irrelevant.

It's highly relevant if you're going to have the GC run
user code as it's collecting objects!

> As long as they are not reachable there is no need to
> manipulate pointer values during destruction in order
> to maintain the correctness of the data structure.

But you're proposing to run user-written destructors
during collection! The data structures had better be
correct if you're going to run code on them.

> I think you refer to resurrection here, which has been
> well covered elsewhere. There is no perfect solution.

Yes there is. Collect the memory, don't run any code.

> No, the example code showed an explicit call of the
> constructor on an already constructed object. No
> destructor call was skipped.

The destructor of the first object constructed was
skipped.

> In other words the lifetime of the object was:

No, there were two objects there.

>>In the words of the standard, a collected object is
>>never released, only reused.

"Released" and "reused" are words of the standard.
I am applying them to what I think GC should do.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: brangdon@cix.co.uk (Dave Harris)
Date: Sun, 16 Jun 2002 05:49:09 GMT
Raw View
glancaster@ntlworld.com (Garry Lancaster) wrote (abridged):
> Are you suggesting a GC that *never* calls finalizers/
> destructors or just one that skips them for objects
> remaining at program termination? I understood the
> suggestion was the latter [...]

I intended the former. In my view, finalisers complicate the model more
than they are worth, because of the resurrection problem. And destructors
are even worse, because they make for undefined behaviour.

I am suggesting a model very similar to the one we have today. Failure to
de-allocate an object which owns resources would be a leak. The difference
is that memory resources could be reclaimed. Thus it is only a bug if the
object owns non-memory resources.

I think it is a mistake to rely on GC for non-memory resources.

  Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
      brangdon@cix.co.uk      |   And close your eyes with holy dread,
                              |  For he on honey dew hath fed
 http://www.bhresearch.co.uk/ |   And drunk the milk of Paradise."

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: brangdon@cix.co.uk (Dave Harris)
Date: Sun, 16 Jun 2002 05:49:16 GMT
Raw View
hyrosen@mail.com (Hyman Rosen) wrote (abridged):
> > What /is/ worth while is weak pointers. That is, a pointer which (a)
> > does not prevent the thing it points to from being collected, and (b)
> > magically becomes NULL if that ever happens.
>
> How does this interact with concurrent programming or concurrent gc?

There must be a weak-pointer to normal-pointer conversion which does the
right thing for the architecture. This may mean relatively expensive
locks behind the scenes.


> Does every fucntion that uses a weak pointer have to first acquire a
> lock to prevent the pointee from being collected for the duration?

No; they can just extract a normal pointer and hold onto it for the
duration. That will prevent the object from being collected. Eg:

    void print( weak_pointer<Object> weak_p ) {
        Object *normal_p = weak_p;
        if (normal_p != 0)
            cout << *normal_p;
    }

The lock/unlock pair, if needed, is entirely encapsulated by the
weak-pointer.

Probably there should be higher-level objects, such as vectors and maps of
weak-pointers, and there may be ways to specialise algorithms such std
std::find() to minimise the number of locks.


> And as someone already said, if you're doing all this analysis to
> decide what kind of pointer to use, you're back in C++ smart-pointer
> land anyway.

Weak-pointers are rarely needed; they are a solution to a problem and you
don't even consider them unless you have that problem. And then you need
them badly.

In general, garbage collection doesn't absolve us from needing to do
object life-time analysis.

  Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
      brangdon@cix.co.uk      |   And close your eyes with holy dread,
                              |  For he on honey dew hath fed
 http://www.bhresearch.co.uk/ |   And drunk the milk of Paradise."

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Hyman Rosen <hyrosen@mail.com>
Date: Sun, 16 Jun 2002 05:50:19 GMT
Raw View
Garry Lancaster wrote:
> I think you are attempting to define "memory leak", not
> "leak", which is more general because it covers any
> resource.

No. Leaks occur when there is no possibility of reclaiming
a resource because all refernces to it within the program
are gone. For example, if I say fopen("joe", "a") without
saving the return value, I have leaked an open file. It
generally matters only if I can do this an arbitrary number
of times in the run of a program, or if it is a resource
which is not reclaimed by program termination.

> In general, no, this is not perfectly legitimate. In general
> it is a leak. A bug. The reason being that there is nothing
> in the C++ standard that guarantees it (and all resources
> it owns) *will* simply "go away at program termination".

I refer you to 1.9/6. The standard also doesn't guarantee
anything about resources even if you do run destructors.
The only behavior the standard guarantees is access to
volatile objects and I/O. It is perfectly standard conforming
for a C++ implementation to never allow allocated memory to
be reused - one can imagine an implementation which uses a
write-once CD-ROM as its memory!

I also refer you to 3.8/1 where the standard explicitly
blesses the notion of ending the lifetime of an object
by reusing its memory instead of releasing it.

> If there is no difference in observable behaviour between
> program termination with or without the destructor call then
> the compiler can elide the destructor call.

This is charmingly naive. I am supposed to deliberately
initiate a lengthy and useless operation, and the compiler
is supposed to notice that it's useless and not do it?
When I can simply not do it to begin with?

> Your example is illuminating. You are assuming that
> destroying a tree node leads to the tree adjusting its
> internal pointers.

I am assuming a complicated and cross-linked structure,
so that when objects start being destroyed, they remove
themselves from maps, and that happens one-at-a-time,
and those maps rebelance themselves because of it. This
has nothing at all to do with GC.

> Are you suggesting a GC that *never* calls finalizers/
> destructors or just one that skips them for objects
> remaining at program termination?

Never.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Garry Lancaster" <glancaster@ntlworld.com>
Date: Mon, 17 Jun 2002 18:01:54 GMT
Raw View
Garry Lancaster:
> > Are you suggesting a GC that *never* calls finalizers/
> > destructors or just one that skips them for objects
> > remaining at program termination? I understood the
> > suggestion was the latter [...]

Dave Harris:
> I intended the former.

Then you seek a more restrictive model than Java, C#
or Boehm et al.

Do you want an object with a dtor to be garbage collectable,
but just have the dtor silently ignored. Or would you not
allow an objects with a dtor to be garbage collectable?

> In my view, finalisers complicate the model more
> than they are worth, because of the resurrection problem.
> And destructors are even worse, because they make for
> undefined behaviour.

Why do you think running a destructor leads to
undefined behaviour?

[snip]

Kind regards

Garry Lancaster
Codemill Ltd
Visit our web site at http://www.codemill.net


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Garry Lancaster" <glancaster@ntlworld.com>
Date: Wed, 12 Jun 2002 18:25:42 GMT
Raw View
John Nagle:
> We need to clearly
> distinguish between objects with standard C++
> destructor semantics, and objects with other
> semantics.

There shouldn't be any objects with "other semantics".
All objects must eventually have their destructors run,
just as is the case today.

Kind regards

Garry Lancaster
Codemill Ltd
Visit our web site at http://www.codemill.net

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: brangdon@cix.co.uk (Dave Harris)
Date: Wed, 12 Jun 2002 22:46:11 GMT
Raw View
glancaster@ntlworld.com (Garry Lancaster) wrote (abridged):
> > We need to clearly distinguish between objects with standard C++
> > destructor semantics, and objects with other semantics.
>
> There shouldn't be any objects with "other semantics".
> All objects must eventually have their destructors run,
> just as is the case today.

But surely that isn't the case today. If I allocate an object with new,
and never destroy it with delete, its destructor will never be called.
Not even when the program exits.

I see no reason why GC should change this. In my view, it is the job of GC
to give the illusion of infinite memory. The notion of GC doing something
just before an object's storage is reclaimed, is almost an oxymoron. As
far as the programmer is concerned, memory is infinite and objects are
never reclaimed.

  Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
      brangdon@cix.co.uk      |   And close your eyes with holy dread,
                              |  For he on honey dew hath fed
 http://www.bhresearch.co.uk/ |   And drunk the milk of Paradise."

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Garry Lancaster" <glancaster@ntlworld.com>
Date: Thu, 13 Jun 2002 16:23:49 GMT
Raw View
John Nagle:
> > > We need to clearly distinguish between objects with standard C++
> > > destructor semantics, and objects with other semantics.

Garry Lancaster:
> > There shouldn't be any objects with "other semantics".
> > All objects must eventually have their destructors run,
> > just as is the case today.

Dave Harris:
> But surely that isn't the case today. If I allocate an object with new,
> and never destroy it with delete, its destructor will never be called.
> Not even when the program exits.

And generally we would say that was a leak. A bug.

> I see no reason why GC should change this. In my view, it is the job of GC
> to give the illusion of infinite memory. The notion of GC doing something
> just before an object's storage is reclaimed, is almost an oxymoron. As
> far as the programmer is concerned, memory is infinite and objects are
> never reclaimed.

If the only thing that destructors ever did was reclaim
resources that were automatically reclaimed at program
exit anyway you might have a point. But as I hope we all
know that is not the case.

Kind regards

Garry Lancaster
Codemill Ltd
Visit our web site at http://www.codemill.net

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Alexander Terekhov <terekhov@web.de>
Date: Thu, 13 Jun 2002 16:25:45 GMT
Raw View
Dave Harris wrote:
>
> glancaster@ntlworld.com (Garry Lancaster) wrote (abridged):
> > > We need to clearly distinguish between objects with standard C++
> > > destructor semantics, and objects with other semantics.
> >
> > There shouldn't be any objects with "other semantics".
> > All objects must eventually have their destructors run,
> > just as is the case today.
>
> But surely that isn't the case today. If I allocate an object with new,
> and never destroy it with delete, its destructor will never be called.
> Not even when the program exits.
>
> I see no reason why GC should change this. In my view, it is the job of GC
> to give the illusion of infinite memory. The notion of GC doing something
> just before an object's storage is reclaimed, is almost an oxymoron. As
> far as the programmer is concerned, memory is infinite and objects are
> never reclaimed.

Yes, but that's just one 'policy' (the one that works really good with
trivial d-tors, though ;-)). Other policies could make sense as well.

regards,
alexander.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: remove.haberg@matematik.su.se (Hans Aberg)
Date: Thu, 13 Jun 2002 23:55:40 GMT
Raw View
In article <memo.20020612234124.34267H@brangdon.madasafish.com>,
brangdon@cix.co.uk wrote:
>> There shouldn't be any objects with "other semantics".
>> All objects must eventually have their destructors run,
>> just as is the case today.

>But surely that isn't the case today. If I allocate an object with new,
>and never destroy it with delete, its destructor will never be called.
>Not even when the program exits.

>I see no reason why GC should change this. In my view, it is the job of GC
>to give the illusion of infinite memory. The notion of GC doing something
>just before an object's storage is reclaimed, is almost an oxymoron. As
>far as the programmer is concerned, memory is infinite and objects are
>never reclaimed.

In C++, the story is more complicated, because memory is not the only
resource controlled using constructors/destructors: There is a semantic
aspect as well.

For example, an object may signal something when it is destroyed. The
question is: When should this happen if one is using a conservative GC? --
Traditionally, this is done via a "delete" that sends a signal to the
object destructors, before they are destroyed.

With a conservative GC in place, one may wonder when this semantic signal
should be sent: When the object that maintains the pointer is destroyed by
C++ "automatic" context and forwards a destructor signal by that, or when
the GC decides that it is time to reclaim memory?

-- The way I see it, there is no general semantic formula to that dilemma:
Some objects may prefer the one, and others the other, or make use of a
combination of the two. Thus one will have to live with both traditional
C++ destructors (~X) and in addition new finalizers (that perhaps should
be called ~~X then).

In addition to that, I have a hunch that finalizers may be used in helping
the implementation of GC's.

  Hans Aberg      * Anti-spam: remove "remove." from email address.
                  * Email: Hans Aberg <remove.haberg@member.ams.org>
                  * Home Page: <http://www.matematik.su.se/~haberg/>
                  * AMS member listing: <http://www.ams.org/cml/>

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Ryjek <ryjek@cox.net>
Date: Thu, 13 Jun 2002 23:56:13 GMT
Raw View
Garry Lancaster wrote:
> John Nagle:
>
>>We need to clearly
>>distinguish between objects with standard C++
>>destructor semantics, and objects with other
>>semantics.
>
>
> There shouldn't be any objects with "other semantics".
> All objects must eventually have their destructors run,
> just as is the case today.

No. Destructors should be run only for objects that go out of scope or
for objects that are explicitly deleted.

For garbage collected objects, no destructors should be called.

If you need your resource to be released at a predictable time in some
object's destructor, that object lifetime must not depend on anything
garbage collected.

Just my $.02

> Kind regards
>
> Garry Lancaster
> Codemill Ltd
> Visit our web site at http://www.codemill.net
>
> ---
> [ comp.std.c++ is moderated.  To submit articles, try just posting with ]
> [ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
> [              --- Please see the FAQ before posting. ---               ]
> [ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]
>


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Hyman Rosen <hyrosen@mail.com>
Date: Thu, 13 Jun 2002 23:57:21 GMT
Raw View
Garry Lancaster wrote:
> Dave Harris:
>>But surely that isn't the case today. If I allocate an object with new,
>>and never destroy it with delete, its destructor will never be called.
>>Not even when the program exits.
>
> And generally we would say that was a leak. A bug.

No. Leaks occur (in the C or C++ sense) when there exist no
pointers to allocated memory, and more generally, when this
can happen an arbitrary number of times during the run of the
program. It is perfectly legitimate to allocate an object with
the intention of never freeing it, and simply allowing it to
go away at program termination.

For example, your crossword puzzle builder may have loaded its
dictionary and created all sorts of maps involving the words.
Cleaning this up could involve potentially hundreds of thousands
of deallocations and tree rebalancings, causing all sorts of
memory to be paged in from disk, all to absolutely no purpose.
Instead, you just let the whole thing die with the program.

>>I see no reason why GC should change this. In my view, it is the job of GC
>>to give the illusion of infinite memory. The notion of GC doing something
>>just before an object's storage is reclaimed, is almost an oxymoron. As
>>far as the programmer is concerned, memory is infinite and objects are
>>never reclaimed.
>
> If the only thing that destructors ever did was reclaim
> resources that were automatically reclaimed at program
> exit anyway you might have a point. But as I hope we all
> know that is not the case.

If you want a destructor, then write a destructor. Destructors
run at deterministic points in the program. But it's absolutely
correct that GC is meant to simulate infinite memory. Apropos
of what you said above, one uses GC by deliberately causing
memory leaks, that is, losing track of all pointers to an object.
Then as far the program is concerned, the object may live on
forever. This also neatly sidesteps the issue of finalizers
revivifying objects which ought to be dead.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: brangdon@cix.co.uk (Dave Harris)
Date: Fri, 14 Jun 2002 14:16:42 GMT
Raw View
terekhov@web.de (Alexander Terekhov) wrote (abridged):
> > I see no reason why GC should change this. In my view, it is the job
> > of GC to give the illusion of infinite memory. The notion of GC doing
> > something just before an object's storage is reclaimed, is almost
> > an oxymoron. As far as the programmer is concerned, memory is
> > infinite and objects are never reclaimed.
>
> Yes, but that's just one 'policy' (the one that works really good with
> trivial d-tors, though ;-)). Other policies could make sense as well.

I don't think they do. In my experience with GC'd languages (mostly
Smalltalk and Java), there is little of real value which finalisers can
do. They are mostly for debugging. A typical finaliser looks like:

    void File::finalise() {
        if (isOpen())
            throw "You forgot to close me!";
    }

and merely detects logic errors in the code. This can be quite useful but
it is hardly worth the language complication. We can't rely on non-trivial
behaviour in production code because finalisation may be delayed
indefinitely.

What /is/ worth while is weak pointers. That is, a pointer which (a) does
not prevent the thing it points to from being collected, and (b) magically
becomes NULL if that ever happens. This is a low-level concept but can be
very important practically. It avoids the conceptual problems of
finalisers reviving their objects.

Weak pointers can replace some of the things finalisers/destructors might
be used for. They remove the need for objects to unregister themselves
from tables, for example; instead the table uses a weak-pointer to the
object and thus can discover for itself when the object is gone.

Perhaps the (b) part could be generalised a bit. Rather of GC invoking the
finaliser on the object that is to be collected, we could register some
/other/ object to receive the notification. Again there would be no way
for the other object to revive the collected one.

  Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
      brangdon@cix.co.uk      |   And close your eyes with holy dread,
                              |  For he on honey dew hath fed
 http://www.bhresearch.co.uk/ |   And drunk the milk of Paradise."

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Hyman Rosen <hyrosen@mail.com>
Date: Fri, 14 Jun 2002 17:36:59 GMT
Raw View
Dave Harris wrote:
> What /is/ worth while is weak pointers. That is, a pointer which (a) does
> not prevent the thing it points to from being collected, and (b) magically
> becomes NULL if that ever happens.

How does this interact with concurrent programming or concurrent gc?
Does every fucntion that uses a weak pointer have to first acquire a
lock to prevent the pointee from being collected for the duration?
Otherwise, I don't see how they could be used at all, since they can
go away between a test for null and a use.

And as someone already said, if you're doing all this analysis to
decide what kind of pointer to use, you're back in C++ smart-pointer
land anyway.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Garry Lancaster" <glancaster@ntlworld.com>
Date: Sat, 15 Jun 2002 06:17:50 GMT
Raw View
Dave Harris:
> >>But surely that isn't the case today. If I allocate an object with new,
> >>and never destroy it with delete, its destructor will never be called.
> >>Not even when the program exits.

Garry Lancaster:
> > And generally we would say that was a leak. A bug.

Hyman Rosen:
> No. Leaks occur (in the C or C++ sense) when there exist no
> pointers to allocated memory, and more generally, when this
> can happen an arbitrary number of times during the run of the
> program.

I think you are attempting to define "memory leak", not
"leak", which is more general because it covers any
resource.

> It is perfectly legitimate to allocate an object with
> the intention of never freeing it, and simply allowing it to
> go away at program termination.

In general, no, this is not perfectly legitimate. In general
it is a leak. A bug. The reason being that there is nothing
in the C++ standard that guarantees it (and all resources
it owns) *will* simply "go away at program termination".

> For example, your crossword puzzle builder may have loaded its
> dictionary and created all sorts of maps involving the words.
> Cleaning this up could involve potentially hundreds of thousands
> of deallocations and tree rebalancings, causing all sorts of
> memory to be paged in from disk, all to absolutely no purpose.
> Instead, you just let the whole thing die with the program.

If there is no difference in observable behaviour between
program termination with or without the destructor call then
the compiler can elide the destructor call. This is nothing
new in C++: it is covered by the "as-if" rule. I would expect
compiler vendors to make this optimization for objects
with trivial destruction semantics, but not necessarily
for other objects.

Your example is illuminating. You are assuming that
destroying a tree node leads to the tree adjusting its
internal pointers. I think that with a GC-based tree structure
it will be the other way around: adjustment of internal
pointers leads to collection of discarded nodes. Nodes
of simple GC-based tree structures are actually one of the
many objects that can, under GC, have trivial destruction
semantics. This means that at program termination the
nodes can be de-allocated together without any user-
supplied code being run. Under OSs that return outstanding
allocated heap memory to the system automatically at
program termination (i.e. most of them) even the de-
allocation can be avoided, under "as-if".

> >>I see no reason why GC should change this. In my view, it is the job of
GC
> >>to give the illusion of infinite memory. The notion of GC doing
something
> >>just before an object's storage is reclaimed, is almost an oxymoron. As
> >>far as the programmer is concerned, memory is infinite and objects are
> >>never reclaimed.
> >
> > If the only thing that destructors ever did was reclaim
> > resources that were automatically reclaimed at program
> > exit anyway you might have a point. But as I hope we all
> > know that is not the case.
>
> If you want a destructor, then write a destructor.

That is exactly what I do.

> Destructors run at deterministic points in the program.

A lot has been said on the subject of determinism vs.
non-determinism already on the thread, so there seems
very little point in repeating it all. If you still want to discuss
it, start by defining your terms.

> But it's absolutely
> correct that GC is meant to simulate infinite memory. Apropos
> of what you said above, one uses GC by deliberately causing
> memory leaks, that is, losing track of all pointers to an object.

I don't believe your definition of memory leak is
appropriate. I would agree with it if it were not for
the fact that it ignores the references to objects
held internally by the GC system.

> Then as far the program is concerned, the object may live on
> forever. This also neatly sidesteps the issue of finalizers
> revivifying objects which ought to be dead.

Are you suggesting a GC that *never* calls finalizers/
destructors or just one that skips them for objects
remaining at program termination? I understood the
suggestion was the latter, in which case the
resurrection problem is still present for those objects
collected prior to program termination. If the former,
this is going further than the Boehm et al., Java and
C# GC systems.

Kind regards

Garry Lancaster
Codemill Ltd
Visit our web site at http://www.codemill.net

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: John Nagle <nagle@animats.com>
Date: Tue, 11 Jun 2002 17:59:49 GMT
Raw View
William E. Kempf wrote:

> "Daniel Miller" <daniel.miller@tellabs.com> wrote in message
> news:3D0531FC.7040803@tellabs.com...
>
>>   I have never claimed that anything would be *removed*.  I am stating
>>that the distracting presence of finalizers as a competitor to &
>>displacer of dtors clouds RAII to the point that XAOP is eroded.
>>
> This is the crux of the disagreement, I think.  The above is FUD, with no
> data to back it up.  Is it possible that this fear may turn out to be
> correct?  Yes, but I doubt it.  Especially in domains such as yours where
> XAOP is so important and RAII provides a cleaner solution then those
> employed by other GCed languages.


     The acronyms are getting a bit out of hand here.

     But Miller has a point.  We need to clearly
distinguish between objects with standard C++
destructor semantics, and objects with other
semantics.

     John Nagle
     Animats

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: remove.haberg@matematik.su.se (Hans Aberg)
Date: Wed, 12 Jun 2002 16:08:49 GMT
Raw View
In article <3D06383B.4060108@animats.com>, John Nagle <nagle@animats.com> wrote:
>     But Miller has a point.  We need to clearly
>distinguish between objects with standard C++
>destructor semantics, and objects with other
>semantics.

An idea that comes to my mind is that objects may need to be made "GC
aware", a property that somehow should be communicated via the C++
language.

With such a concept in hand, it may be easier to introduce GC support into C++.

  Hans Aberg      * Anti-spam: remove "remove." from email address.
                  * Email: Hans Aberg <remove.haberg@member.ams.org>
                  * Home Page: <http://www.matematik.su.se/~haberg/>
                  * AMS member listing: <http://www.ams.org/cml/>

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]