By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
459,403 Members | 1,360 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 459,403 IT Pros & Developers. It's quick & easy.

Garbage collection in C++

P: n/a
Hi all,

Is garbage collection possible in C++. It doesn't come as part of
language support. Is there any specific reason for the same due to the
way the language is designed. Or it is discouraged due to
some specific reason. If someone can give inputs on the same, it will
be of great help.

Regards,
Pushpa
Nov 15 '08
Share this Question
Share on Google+
158 Replies


P: n/a
zr
On Nov 18, 4:08*pm, Matthias Buelow <m...@incubus.dewrote:
zr wrote:
How can GC improve the performance of a multithreaded application? Can
you show a convincing example?

Many of today's programs (OO or not) have a high
allocation(/deallocation) rate. This means that most objects become
garbage quickly. With many GCs, their collection time is a function of
the amount of live data, that is, they don't have to traverse the
garbage at all. This means in total, in such a situation, there's less
work to do than in a manual deallocation scheme, where all the garbage
is being traversed aswell.
I don't know if multithreading is any factor here; with manual schemes,
you have to do synchronization, too.
But even if in these (rare/common) cases where GC can improve
performance over manual deallocation, isn't there a better solution
which would give better performance than GC? Is performance a real
consideration for adding GC to the language?
Nov 18 '08 #51

P: n/a
zr wrote:
But even if in these (rare/common) cases where GC can improve
performance over manual deallocation, isn't there a better solution
which would give better performance than GC? Is performance a real
consideration for adding GC to the language?
No, convenience is. If it increases performance, all the better.
Nov 18 '08 #52

P: n/a
Chris M. Thomasson wrote:
>
"James Kanze" <ja*********@gmail.comwrote in message
news:39**********************************@w1g2000p rk.googlegroups.com...
On Nov 16, 3:54 pm, Sam <s...@email-scan.comwrote:
[...]
So they seek for a security blanket called "garbage
collection", so they don't have to worry about it, and can
proceed to churn out their spaghetti code without worry, just
like they do in Java.
>That is, of course, the most obvious bullshit I've ever seen.
There are cases where garbage collection isn't appropriate, and
cases where it is necessary.

Humm.. Can you give an example or two of a scenario in which a GC is
absolutely required/necessary? For some reason, I can't seem to think of
one off the top of my head. What am I missing? Perhaps I misunderstand
your use of the word "necessary"...

1) without gc

class A
{
};

A* foo()
{
A *a = NULL;
A *b = NULL;

a = new A;
try
{
b = new A;
}
catch(...)
{
delete(a);
}

// do something

return a;
}

2) with GC
class A
{
};

A* foo()
{
std::auto_ptr< A a( new A );
std::auto_ptr< A b( new A );

// do something

return a.release();
}
Would this do?
Another example:

class X
{
public:
X()
{
throw 1111;
}
};

class A
{
public:
A() : a( new int ), b( new X )
{
}
// memory leak when b throws

int *a;
X *b;
};

vs

class A
{
public:
A() : a( new int ), b( new X )
{
}
// OK

std::auto_ptr< int a;
std::auto_ptr< X b;
};
Nov 18 '08 #53

P: n/a
"Matthias Buelow" <mk*@incubus.dewrote in message
news:6o************@mid.dfncis.de...
Keith H Duggar wrote:
>Yes. However, garbage collection is /only/ going to reclaim
memory, eventually. It's not going to correct the logical and
potentially far more serious design bugs that leaked memory
in the first place.

Yes, GC does not correct any bugs, you're right about that ;). However,
there are many situations where having to do manual deallocation is just
additional work without any benefit. For example, if you're doing a lot
of tree handling, building trees, throwing them away again etc., you
don't really want to traverse the tree to free all the elements if you
throw it away. Much more convenient to simply "forget" the pointer to
the tree and let automatic memory management wipe it up.
I would build a node cache for the trees; why free the memory when you can
reuse some of it? You can do this in a GC environment, but it requires you
to traverse a "portion" of the tree.

Also, why not use a __partitioned__ region allocation algorithm for the
nodes in different trees? That way, a single call to `std::free()' will
promptly destroy all the memory which makes up a given trees nodes in a
single operation. AFAICT, that's more efficient than a GC. Region allocation
is not complicated and drastically amortizes the number of times you need to
call free.

Generally, I find that "clever" __partitioned__ region allocation can give
you the best of both worlds... You get deterministic manual memory
management, and the calls to free get heavily amortized.

(This is a bit relativized if you have a situation where you need to
have destructors run in tree nodes; in general, the concepts of
destructors and GC don't really work well together, and imho,
destructors are rather an ugly add-hoc hack that stems from the lack of
automatic memory management and because of that unfortunately has firmly
established itself in C++...)
I think dtors are very convenient...

Nov 18 '08 #54

P: n/a
Chris M. Thomasson wrote:
Generally, I find that "clever" __partitioned__ region allocation can
give you the best of both worlds...
You seem to completely fail to understand the point I was trying to
make: Using GC in my example is not to speed up the program, or
whatever, but to avoid even having to think abut this. "Clever"
partition schemes or whatever need thinking effort, that could be
directed at more interesting parts of the program than memory management.
Nov 18 '08 #55

P: n/a
On Nov 18, 2:41 pm, Matthias Buelow <m...@incubus.dewrote:
Keith H Duggar wrote:
Yes. However, garbage collection is /only/ going to reclaim
memory, eventually. It's not going to correct the logical
and potentially far more serious design bugs that leaked
memory in the first place.
Yes, GC does not correct any bugs, you're right about that ;).
However, there are many situations where having to do manual
deallocation is just additional work without any benefit.
Exactly.
For example, if you're doing a lot of tree handling, building
trees, throwing them away again etc., you don't really want to
traverse the tree to free all the elements if you throw it
away. Much more convenient to simply "forget" the pointer to
the tree and let automatic memory management wipe it up.
(This is a bit relativized if you have a situation where you
need to have destructors run in tree nodes; in general, the
concepts of destructors and GC don't really work well
together, and imho, destructors are rather an ugly add-hoc
hack that stems from the lack of automatic memory management
and because of that unfortunately has firmly established
itself in C++...)
Yes and no. Destructors and garbage collection are in some ways
orthogonal; destructors are exceedingly useful for local
variables, where they effectively replace finally blocks, only
with the provision that the client can't forget them when
needed. They are much less useful elsewhere, except for
substituting for garbage collection.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Nov 18 '08 #56

P: n/a
On Nov 18, 4:15 pm, "Chris M. Thomasson" <n...@spam.invalidwrote:
"Matthias Buelow" <m...@incubus.dewrote in message
news:6o************@mid.dfncis.de...
Keith H Duggar wrote:
Yes. However, garbage collection is /only/ going to reclaim
memory, eventually. It's not going to correct the logical and
potentially far more serious design bugs that leaked memory
in the first place.
Yes, GC does not correct any bugs, you're right about that
;). However, there are many situations where having to do
manual deallocation is just additional work without any
benefit. For example, if you're doing a lot of tree
handling, building trees, throwing them away again etc., you
don't really want to traverse the tree to free all the
elements if you throw it away. Much more convenient to
simply "forget" the pointer to the tree and let automatic
memory management wipe it up.
I would build a node cache for the trees;
In other words, extra work. That's exactly what Matthias was
arguing against.
why free the memory when you can reuse some of it?
Why do extra work when you don't have to?
You can do this in a GC environment, but it requires you to
traverse a "portion" of the tree.
Also, why not use a __partitioned__ region allocation
algorithm for the nodes in different trees? That way, a single
call to `std::free()' will promptly destroy all the memory
which makes up a given trees nodes in a single operation.
AFAICT, that's more efficient than a GC.
For the programmer? Since when is writing additional code more
efficient.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Nov 18 '08 #57

P: n/a
"Matthias Buelow" <mk*@incubus.dewrote in message
news:6o************@mid.dfncis.de...
Chris M. Thomasson wrote:
>Generally, I find that "clever" __partitioned__ region allocation can
give you the best of both worlds...

You seem to completely fail to understand the point I was trying to
make: Using GC in my example is not to speed up the program, or
whatever, but to avoid even having to think abut this. "Clever"
partition schemes or whatever need thinking effort,
Does GC promote a nanny state? Just kidding! Anyway, partitioned region
allocation schemes can definitely help reduce your "thinking effort". For
instance, take this very simple C pseudo-code into account:


static struct region_allocator g_ralloc = REGION_STATIC_INIT;
static struct tree g_tree1 = TREE_STATIC_INIT;
static struct tree g_tree2 = TREE_STATIC_INIT;
static struct tree g_tree3 = TREE_STATIC_INIT;
static struct tree g_tree4 = TREE_STATIC_INIT;
int main(void) {
unsigned i;
struct region_partition* rp1 = region_allocate(&g_ralloc, 4096);
struct region_partition* rp2 = region_allocate(&g_ralloc, 4096);

for (i = 0; i < 1234; ++i) {
struct node* node1 = region_partition_allocate(rp1, sizeof(*node));
struct node* node2 = region_partition_allocate(rp1, sizeof(*node));
struct node* node3 = region_partition_allocate(rp2, sizeof(*node));
struct node* node4 = region_partition_allocate(rp2, sizeof(*node));
tree_push(&g_tree1, node1);
tree_push(&g_tree2, node2);
tree_push(&g_tree3, node3);
tree_push(&g_tree4, node4);
}

region_flush(&g_ralloc);

return 0;
};


No need to explicitly traverse all of the trees. Instead, one single call to
`region_flush()' results in the automatic freeing of all its contained
partitions. You could also free individual partitions. See how it eliminates
the need to free individual nodes? Also, more than one tree can share a
single partition. In the example, trees 1-2 share partition 1, and trees 3-4
share partition 2. IMVHO, its a fairly flexible allocation scheme indeed.

that could be
directed at more interesting parts of the program than memory management.
IMVHO, efficient memory management is an interesting part of any program...
Humm...

Nov 18 '08 #58

P: n/a
"James Kanze" <ja*********@gmail.comwrote in message
news:10**********************************@a26g2000 prf.googlegroups.com...
On Nov 18, 4:15 pm, "Chris M. Thomasson" <n...@spam.invalidwrote:
"Matthias Buelow" <m...@incubus.dewrote in message
news:6o************@mid.dfncis.de...
Keith H Duggar wrote:
>Yes. However, garbage collection is /only/ going to reclaim
>memory, eventually. It's not going to correct the logical and
>potentially far more serious design bugs that leaked memory
>in the first place.
Yes, GC does not correct any bugs, you're right about that
;). However, there are many situations where having to do
manual deallocation is just additional work without any
benefit. For example, if you're doing a lot of tree
handling, building trees, throwing them away again etc., you
don't really want to traverse the tree to free all the
elements if you throw it away. Much more convenient to
simply "forget" the pointer to the tree and let automatic
memory management wipe it up.
I would build a node cache for the trees;
In other words, extra work. That's exactly what Matthias was
arguing against.
why free the memory when you can reuse some of it?
Why do extra work when you don't have to?
You can do this in a GC environment, but it requires you to
traverse a "portion" of the tree.
A node cache reduces the number of calls to `new'; IMHO, this is a good
thing.

Also, why not use a __partitioned__ region allocation
algorithm for the nodes in different trees? That way, a single
call to `std::free()' will promptly destroy all the memory
which makes up a given trees nodes in a single operation.
AFAICT, that's more efficient than a GC.
For the programmer?
For the program.

Since when is writing additional code more efficient.
Its worth it that extra work increases the scalability, throughput and
performance of a program.

Nov 18 '08 #59

P: n/a
"Matthias Buelow" <mk*@incubus.dewrote in message
news:6o************@mid.dfncis.de...
zr wrote:
>How can GC improve the performance of a multithreaded application? Can
you show a convincing example?

Many of today's programs (OO or not) have a high
allocation(/deallocation) rate. This means that most objects become
garbage quickly. With many GCs, their collection time is a function of
the amount of live data, that is, they don't have to traverse the
garbage at all. This means in total, in such a situation, there's less
work to do than in a manual deallocation scheme, where all the garbage
is being traversed aswell.
I don't know if multithreading is any factor here; with manual schemes,
you have to do synchronization, too.
There are multi-threaded allocation algorihtms that do not need any
synchronization whatsoever on thread local allocations/deallocations from a
region that is not empty. Remote deallocations can be implemented wait-free
with a single atomic fetch-and-add, or lock-free with a simple
compare-and-swap loop. Here is a very crude and quick example of one:

http://webpages.charter.net/appcore/...em_thread.html

Nov 18 '08 #60

P: n/a
Chris M. Thomasson wrote:
There are multi-threaded allocation algorihtms that do not need any
synchronization whatsoever on thread local allocations/deallocations
from a region that is not empty.
Very good; I would think that this can (and is being) implemented for
automatic memory management, too. In the trivial case (no inter-thread
dependencies), it is obvious, and in other cases, you still have the
same synchronization problem with manual management, only it might've
moved from the alloc/dealloc routines into the application logic.
Nov 18 '08 #61

P: n/a
Chris M. Thomasson wrote:
Closing a file handle in a dtor can be _very_ problematic indeed; read
here:
Not more problematic than leaving the file handle open. (Besides, the
file handle was just an *example*.)
Nov 18 '08 #62

P: n/a

"Juha Nieminen" <no****@thanks.invalidwrote in message
news:jy*************@read4.inet.fi...
Chris M. Thomasson wrote:
>Closing a file handle in a dtor can be _very_ problematic indeed; read
here:

Not more problematic than leaving the file handle open.
How do you know that the dtor of the file wrapper object actually closed the
file? The system specific file close function can fail; think along the
lines of POSIX 'fclose()'

(Besides, the file handle was just an *example*.)
I was nit-picking; sorry about that.

:^/

Nov 18 '08 #63

P: n/a
James Kanze wrote:
destructors are exceedingly useful for local
variables, where they effectively replace finally blocks, only
with the provision that the client can't forget them when
needed. They are much less useful elsewhere, except for
substituting for garbage collection.
Memory is not the only resource which needs managing. (And even in
some cases what you are managing *is* memory, but not memory which a GC
can collect. Eg. the "memory" being managed might be, for example, an
mmapped file or a bitmap in the display hardware.)

Also sometimes even when managing pure memory, you might still want to
do something special before deallocating. (Weak pointers are a very good
example.)
Nov 18 '08 #64

P: n/a
Hans Bos wrote:
Are saying that people that can't make proper programs using garbage
collection will make good programs without gc?
No. I'm saying that people who are fluent in programming might be more
tempted to write imperative code rather than modular code when they have
a GC engine available. After all, the imperative code usually requires
less writing (at least for the first version of the program).
Nov 18 '08 #65

P: n/a
Juha Nieminen wrote:
No. I'm saying that people who are fluent in programming might be more
tempted to write imperative code rather than modular code when they have
a GC engine available. After all, the imperative code usually requires
less writing (at least for the first version of the program).
I really don't understand what you mean by this.

Imperative code is:

foobie = bletch;
blorgh = knork;

Modular imperative code is:

Gront::foobie = Blobbr::bletch;
Krawall::blorgh = Wibbl::knork;

assuming there are modules Gront, Blobbr, Krawall and Wibble, which
contain these entities and :: denotes module resolution.

Manual memory management is imperative. In contrast, automatic memory
management is practically a necessity in non-imperative languages.
Functional languages like ML, Haskell etc. all have automatic memory
management. Lisp has always had GC. It would be totally impractical
attempting to manage memory manually in these high-level languages.
Nov 18 '08 #66

P: n/a
Stefan Ram wrote:
There were two versions of it, one in Lisp and one in
C++. The display subsystem of the Lisp version was faster.
There were various reasons, but an important one was GC:
the C++ code copied a lot of buffers because they got
passed around in fairly complex ways, so it could be quite
difficult to know when one could be deallocated. To avoid
that problem, the C++ programmers just copied. The Lisp
was GCed, so the Lisp programmers never had to worry about
it; they just passed the buffers around, which reduced
both memory use and CPU cycles spent copying.
Yes, it's completely "fair" to compare a C++ program which doesn't
understand the concept of a smart pointer to lisp, where "smart
pointers" (in the sense that memory is garbage-collected) are inherent.

Yes: It requires more work to make that work in C++ with smart
pointers than the same thing in lisp (although making a copy-on-write
version of std::vector is not all that hard). However, that doesn't mean
that the C++ version cannot be as efficient as the lisp version. It only
means the C++ programmers were incompetent.
A lot of us thought in the 1990s that the big battle would
be between procedural and object oriented programming, and
we thought that object oriented programming would provide
a big boost in programmer productivity. I thought that,
too. Some people still think that. It turns out we were
wrong. Object oriented programming is handy dandy, but
it's not really the productivity booster that was
promised. The real significant productivity advance we've
had in programming has been from languages which manage
memory for you automatically.
I still wouldn't trade modules (the most crucial part of OOP) for GC,
if I had to make an excluding choice.
[A]llocation in modern JVMs is far faster than the best
performing malloc implementations. The common code path
for new Object() in HotSpot 1.4.2 and later is
approximately 10 machine instructions (data provided by
Sun; see Resources), whereas the best performing malloc
implementations in C require on average between 60 and 100
instructions per call (Detlefs, et. al.; see Resources).
I like how this misses one of the main reasons why memory allocation
can be slow: Cache behavior.

From experience I would estimate that the number of instructions
executed when allocating/deallocating amounts to maybe 10-20% of the
total speed, and the remaining 80-90% depends on how cache-friendly the
allocation system is. Cache misses are enormously expensive.

Good GC engines do indeed have the advantage that they can defragment
memory and make allocations more cache-friendly. This is harder (but not
impossible) to do in C/C++.
Perhaps the most important realisation I had while developing
this critique is that high level languages are more important
to programming than object-orientation. That is, languages
which have the attribute that they remove the burden of
bookkeeping from the programmer to enhance maintainability and
flexibility are more significant than languages which just
add object-oriented features. While C++ adds object-orientation
to C, it fails in the more important attribute of being high
level. This greatly diminishes any benefits of the
object-oriented paradigm.
On the other hand many "high-level languages" offer abstractions at
the expense of memory usage efficiency. There are "high-level languages"
where it's prohibitively difficult to create very memory-efficient
programs (which handle enormous amounts of data) while still maintaining
a fair amount of abstraction and maintainability.

This seems to have been the trend during the past 10-20 years:
Completely disregard memory usage efficiency in favor of higher level
abstractions. After all, everybody has a supercomputer on their desk and
everything they do with it is play tic-tac-toe. You don't need memory
usage efficiency, right?

C++ might not be all fancy-pancy with all the latest fads in
programming, but at least it offers the tools to write very
memory-efficient programs which are still very well designed, with a
high degree of modularity, abstraction and maintainability. That cannot
be said about all programming languages.
Nov 18 '08 #67

P: n/a
James Kanze wrote:
>>Garbage collection doesn't "encourage" anything.
>I tend to disagree.

Sorry, but it's a statement of fact.
It might be a fact in *your* case. I disagree on it being a fact for
everybody.

I suppose we'd have to just agree to disagree.
Nov 18 '08 #68

P: n/a
Juha Nieminen wrote:
abstractions. After all, everybody has a supercomputer on their desk and
everything they do with it is play tic-tac-toe. You don't need memory
usage efficiency, right?
And what is most of the desktop software written in?
C++ might not be all fancy-pancy with all the latest fads in
programming, but at least it offers the tools to write very
memory-efficient programs which are still very well designed, with a
high degree of modularity, abstraction and maintainability.
However, it seems to be exceedingly difficult to actually do so;
otherwise, why are most of today's applications so slow, memory hogging
and buggy?
Nov 18 '08 #69

P: n/a
Matthias Buelow wrote:
Juha Nieminen wrote:
>By this I mean that since there's no need for
objects to have (memory handling) responsibilities, it easily leads to
the programmer not creating such objects at all,

Isn't that a good thing?
No, because it makes the code less abstract and less modular.
The best code is the one you don't have to
write. Down with bureaucracy. Creating objects just to keep track of
memory dependencies is... inane?
Then don't create objects whose sole purpose is to keep track of
memory dependencies. Create objects which have a purpose and a role in
the entire design.

This might not be the best possible example of what I'm talking about,
but I think it's at least close:

Don't do: SmartArray<charmyString = new char[100];

Instead, do: String myString(100);

The "String" is effectively performing the same bookkeeping job as the
"SmartArray<char>" would, but it's already at a much higher conceptual
and abstraction level, and thus better from a design point of view.

Gargabe collection often tempts writing code like the first example,
rather than code like the second example.
>which in turn leads to
a more imperative style of programming, rather than a more modular style.

Imperative programming and modular programming are orthogonal concepts.
An imperative programming style can be detrimental if overweights the
modularity of the overall design.
Nov 18 '08 #70

P: n/a
"Matthias Buelow" <mk*@incubus.dewrote in message
news:6o************@mid.dfncis.de...
Juha Nieminen wrote:
>abstractions. After all, everybody has a supercomputer on their desk and
everything they do with it is play tic-tac-toe. You don't need memory
usage efficiency, right?

And what is most of the desktop software written in?
> C++ might not be all fancy-pancy with all the latest fads in
programming, but at least it offers the tools to write very
memory-efficient programs which are still very well designed, with a
high degree of modularity, abstraction and maintainability.


However, it seems to be exceedingly difficult to actually do so;
otherwise, why are most of today's applications so slow, memory hogging
and buggy?
Because bloat-ware is cool! ;^D

Why do you think that most of Google is written in C++?

Nov 18 '08 #71

P: n/a
James Kanze wrote:
On Nov 17, 8:29 pm, Juha Nieminen <nos...@thanks.invalidwrote:
>James Kanze wrote:
>>>Sometimes I get the impression that garbage collection
actually causes people to write *less* modular and more
imperative programs. GC doesn't really encourage encapsulation
and modularity.
>>Garbage collection doesn't "encourage" anything.
>I tend to disagree.

Sorry, but it's a statement of fact. Garbage collection is just
a tool; a piece of code. It can't encourage or discourage
anything.
OO is "just a tool", too.
Doesn't it encourage specific ways to program?
(Note that I do not necessarily defend Juha's position.
I just find yours a very weak argument.)
[...]
Schobi
Nov 18 '08 #72

P: n/a
Matthias Buelow wrote:
However, it seems to be exceedingly difficult to actually do so;
otherwise, why are most of today's applications so slow, memory hogging
and buggy?
Becomes the majority of programmers hired out there are incompetent?

A different programming language is not going to help that problem.
Nov 18 '08 #73

P: n/a
Matthias Buelow wrote:
Juha Nieminen wrote:
> No. I'm saying that people who are fluent in programming might be more
tempted to write imperative code rather than modular code when they have
a GC engine available. After all, the imperative code usually requires
less writing (at least for the first version of the program).

I really don't understand what you mean by this.
char* myString = new char[100];

vs.

std::string myString(100, ' ');

(And don't nitpick on the details of the example. It's just an
example. Try to understand my *point*.)

If we had a GC engine, we might be tempted to write like the first
line above because, after all, we don't have to care about the
management of that memory. Of course the first line is extremely
non-abstract: It hard-codes the type, size and geometry of the array,
and exposes that it's accessed through a char pointer.

The second line is the more modular approach: It has encapsulated the
details inside the object, rather than them being exposed. It doesn't
hard-code the array type, it doesn't even hard-code that it *is* a
(contiguous) array, it doesn't hard-code how the array is accessed or
how it's stored in memory, and it doesn't necessarily make the array
fixed in size.

However, if you didn't have a string class like that already handled
to you by a library, the lazy approach would be to use the first method
rather than doing the work of actually encapsulating the whole concept
of "string" into a class.

I feel that a GC engine just gives the incentive to do exactly that:
Skip on the pesky encapsulation and do it in the imperative way. It's
less writing in the short run.
Nov 18 '08 #74

P: n/a
Juha Nieminen wrote:
Don't do: SmartArray<charmyString = new char[100];
Instead, do: String myString(100);

Gargabe collection often tempts writing code like the first example,
rather than code like the second example.
I don't see any truth to this statement at all.
>>a more imperative style of programming, rather than a more modular style.
Imperative programming and modular programming are orthogonal concepts.

An imperative programming style can be detrimental if overweights the
modularity of the overall design.
This sentence doesn't make any sense either. Are you using a gibberish
generator?
Nov 18 '08 #75

P: n/a
Juha Nieminen wrote:
char* myString = new char[100];
vs.
std::string myString(100, ' ');
If we had a GC engine, we might be tempted to write like the first
line above because, after all, we don't have to care about the
management of that memory.
Maybe you would, I wouldn't.
The second line is the more modular approach: It has encapsulated the
details inside the object, rather than them being exposed. It doesn't
hard-code the array type, it doesn't even hard-code that it *is* a
(contiguous) array, it doesn't hard-code how the array is accessed or
how it's stored in memory, and it doesn't necessarily make the array
fixed in size.
And what's that got to do with GC vs. manual memory management?
However, if you didn't have a string class like that already handled
to you by a library, the lazy approach would be to use the first method
rather than doing the work of actually encapsulating the whole concept
of "string" into a class.

I feel that a GC engine just gives the incentive to do exactly that:
Skip on the pesky encapsulation and do it in the imperative way. It's
less writing in the short run.
So you say, the whole incentive for you to abstract is memory handling.
I'm sorry you don't see the more obvious advantages of abstraction.
Automatic memory management is an abstraction in the same way that using
a string datatype over a char array is: it is relieving the programmer
of uninteresting implementation details.
Nov 18 '08 #76

P: n/a
Matthias Buelow wrote:
And what's that got to do with GC vs. manual memory management?
Ok, if you can't or don't want to understand my point, then don't.
Nov 18 '08 #77

P: n/a
Matthias Buelow wrote:
Juha Nieminen wrote:
> Don't do: SmartArray<charmyString = new char[100];
Instead, do: String myString(100);

Gargabe collection often tempts writing code like the first example,
rather than code like the second example.

I don't see any truth to this statement at all.
Then don't.
>>>a more imperative style of programming, rather than a more modular style.
Imperative programming and modular programming are orthogonal concepts.
An imperative programming style can be detrimental if overweights the
modularity of the overall design.

This sentence doesn't make any sense either. Are you using a gibberish
generator?
If you don't want to understand, then so be it.
Nov 18 '08 #78

P: n/a
On Nov 18, 6:12*pm, Juha Nieminen <nos...@thanks.invalidwrote:
James Kanze wrote:
destructors are exceedingly useful for local
variables, where they effectively replace finally blocks, only
with the provision that the client can't forget them when
needed. *They are much less useful elsewhere, except for
substituting for garbage collection.
Memory is not the only resource which needs managing.
And? Garbage collection is only concerned with memory. Other
resources need other tools.
(And even in some cases what you are managing *is* memory, but
not memory which a GC can collect. Eg. the "memory" being
managed might be, for example, an mmapped file or a bitmap in
the display hardware.)
Not sure I follow. There are certainly cases where what
superficially looks like memory isn't memory in the garbage
collector sense; in those cases, you use some other tool.
Also sometimes even when managing pure memory, you might still
want to do something special before deallocating. (Weak
pointers are a very good example.)
Well, most garbage collectors support finalization (which is NOT
the same thing as a destructor); I'll admit, though, that I've
never really found a use for it.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique oriente objet/
Beratung in objektorientierter Datenverarbeitung
9 place Smard, 78210 St.-Cyr-l'cole, France, +33 (0)1 30 23 00 34

Nov 18 '08 #79

P: n/a

"Matthias Buelow" <mk*@incubus.dewrote in message
news:6o************@mid.dfncis.de...
Chris M. Thomasson wrote:
>There are multi-threaded allocation algorihtms that do not need any
synchronization whatsoever on thread local allocations/deallocations
from a region that is not empty.

Very good; I would think that this can (and is being) implemented for
automatic memory management, too.
Absolutely!

In the trivial case (no inter-thread
dependencies), it is obvious, and in other cases, you still have the
same synchronization problem with manual management, only it might've
moved from the alloc/dealloc routines into the application logic.
The internal allocator synchronization is separate from the application
synchronization. So, technically, its was not moved from alloc/dealloc
routines to application. The application always needs to ensure that the
memory it "explicitly" frees is in a persistent quiescent state. GC can
remove the need to follow this requirement.

This is why GC can make the creation of non-blocking algorihtms easier.
However, it has the side-effect of making your algorithm totally GC
dependant. You cannot really port it to a platform that does not have a GC.
Luckily, there are other algorihtms out there than can make non-blocking
algorithms GC independent.

Nov 18 '08 #80

P: n/a
"zr" <zv*****@gmail.comwrote in message
news:4d**********************************@b38g2000 prf.googlegroups.com...
On Nov 17, 11:28 am, James Kanze <james.ka...@gmail.comwrote:
On Nov 16, 11:46 pm, hurcan solter <hsol...@gmail.comwrote:
although it is not strictly necessary , it has its uses with
concurrent programming it may get really confusing the manage
the lifetime of objects when multiple threads
Attention! Garbage collection does NOT manage the lifetime of
objects. It only manages memory. It's generally useful in
multithreaded environments for performance reasons, but it
doesn't address issues as to which thread has the right to
access which objects when. That problem is completely
orthogonal to how you manage memory (unless you're writing the
memory management code yourself, of course).
How can GC improve the performance of a multithreaded application? Can
you show a convincing example?
What about removing the need for atomic reference counting and/or expensive
memory barriers? Of course you don't need a heavy full-blown GC to achieve
that. One can instead make use of an efficient PDR algorithm; PDR stands for
`Partial Copy-On-Write Deferred Reclamation'. The term was coined by Joe
Seigh over on `comp.programming.threads':

http://groups.google.com/group/comp....376b7295e6ce1a
If you wish to lean more about the technique, please ask on that newsgroup.

Nov 18 '08 #81

P: n/a
On Nov 18, 6:36*pm, Juha Nieminen <nos...@thanks.invalidwrote:
Stefan Ram wrote:
* * * There were two versions of it, one in Lisp and one in
* * * C++. The display subsystem of the Lisp version was faster.
* * * There were various reasons, but an important one was GC:
* * * the C++ code copied a lot of buffers because they got
* * * passed around in fairly complex ways, so it could be quite
* * * difficult to know when one could be deallocated. To avoid
* * * that problem, the C++ programmers just copied. The Lisp
* * * was GCed, so the Lisp programmers never had to worry about
* * * it; they just passed the buffers around, which reduced
* * * both memory use and CPU cycles spent copying.
Yes, it's completely "fair" to compare a C++ program which
doesn't understand the concept of a smart pointer to lisp,
where "smart pointers" (in the sense that memory is
garbage-collected) are inherent.
It looks to me like he's comparing to programs which do the same
thing. Probably written by people competent in the language
being used.

I'm familiar with this quote myself. I think it is somewhat
dated; it is comparing C++ as it was written some years ago with
Lisp as it was implemented some years ago. In practice, C++ has
evolved, both with regards to the language, and with regards to
the way competent programmers use it. I don't know about Lisp,
but I do know that garbage collectors have also evolved, and
that modern garbage collection is considerably faster than most
implementations of malloc (which haven't evolved). In many use
patterns, anyway.
Yes: It requires more work to make that work in C++ with smart
pointers than the same thing in lisp (although making a
copy-on-write version of std::vector is not all that hard).
Making one that is multithread safe, and still has the desired
performance, is far from trivial. The experts who wrote the g++
library tried for std::string, and failed. (I'm obviously
ignoring the complexity issues; you can't use copy on write for
a fully conformant implementation of std::vector, because
something like operator[] could no longer be implemented in
constant time.)
However, that doesn't mean that the C++ version cannot be as
efficient as the lisp version. It only means the C++
programmers were incompetent.
Bullshit.
* * * A lot of us thought in the 1990s that the big battle would
* * * be between procedural and object oriented programming, and
* * * we thought that object oriented programming would provide
* * * a big boost in programmer productivity. I thought that,
* * * too. Some people still think that. It turns out we were
* * * wrong. Object oriented programming is handy dandy, but
* * * it's not really the productivity booster that was
* * * promised. The real significant productivity advance we've
* * * had in programming has been from languages which manage
* * * memory for you automatically.
I still wouldn't trade modules (the most crucial part of OOP)
for GC, if I had to make an excluding choice.
I agree, in C++, and if we had any change of getting full
support for modules in C++, in this version, I'd be for it. But
there is no existing practice to base it on, which means that
modules are a lot more work, and involve considerable risk.
* * * [A]llocation in modern JVMs is far faster than the best
* * * performing malloc implementations. The common code path
* * * for new Object() in HotSpot 1.4.2 and later is
* * * approximately 10 machine instructions (data provided by
* * * Sun; see Resources), whereas the best performing malloc
* * * implementations in C require on average between 60 and 100
* * * instructions per call (Detlefs, et. al.; see Resources).
I like how this misses one of the main reasons why memory
allocation can be slow: Cache behavior.
True. For good cache behavior, you need a copying garbage
collector, and I don't think that that's in the cards for C++.
From experience I would estimate that the number of
instructions executed when allocating/deallocating amounts to
maybe 10-20% of the total speed, and the remaining 80-90%
depends on how cache-friendly the allocation system is. Cache
misses are enormously expensive.
How much of a role they play depends largely on the application.
And while a copying collector can definitely have considerably
better locality than any manual allocator, I'm not sure that it
makes a difference in very many programs.
Good GC engines do indeed have the advantage that they can
defragment memory and make allocations more cache-friendly.
This is harder (but not impossible) to do in C/C++.
There has been some research on using a "mostly copying"
collector with C and C++. If I were developing a compiler,
that's the route I'd go. But it requires considerable
collaboration from the compiler.
* * * Perhaps the most important realisation I had while developing
* * * this critique is that high level languages are more important
* * * to programming than object-orientation. That is, languages
* * * which have the attribute that they remove the burden of
* * * bookkeeping from the programmer to enhance maintainability and
* * * flexibility are more significant than languages which just
* * * add object-oriented features. While C++ adds object-orientation
* * * to C, it fails in the more important attribute of being high
* * * level. This greatly diminishes any benefits of the
* * * object-oriented paradigm.
On the other hand many "high-level languages" offer
abstractions at the expense of memory usage efficiency. There
are "high-level languages" where it's prohibitively difficult
to create very memory-efficient programs (which handle
enormous amounts of data) while still maintaining a fair
amount of abstraction and maintainability.
This seems to have been the trend during the past 10-20 years:
Completely disregard memory usage efficiency in favor of
higher level abstractions. After all, everybody has a
supercomputer on their desk and everything they do with it is
play tic-tac-toe. You don't need memory usage efficiency,
right?
Yes and no. In my case, most of the software I write runs on a
single machine, or on just a couple of machines; I'm not writing
shrink-wrapped software. And from a cost point of view, it's
several orders of magnitudes cheaper to configure them with
sufficient memory than it is for me to optimize the memory
footprint down to the last byte. I've known exceptions. One
case where three programmers spend two weaks just to gain 20
some bytes of code. So the program fit into a single ROM,
instead of requiring two. There were seven million examples of
the product built, and six man-weeks was less expensive than
seven million ROM's. But for most people, a couple of KB, or
even a couple of MB more or less aren't going to affect
anything.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique oriente objet/
Beratung in objektorientierter Datenverarbeitung
9 place Smard, 78210 St.-Cyr-l'cole, France, +33 (0)1 30 23 00 34
Nov 18 '08 #82

P: n/a
On Nov 18, 9:47*pm, Juha Nieminen <nos...@thanks.invalidwrote:
Matthias Buelow wrote:
However, it seems to be exceedingly difficult to actually do
so; otherwise, why are most of today's applications so slow,
memory hogging and buggy?
Becomes the majority of programmers hired out there are
incompetent?
Because the majority of companies don't have good development
processes. I don't believe that most programmers are
incompetent.
A different programming language is not going to help that
problem.
Certainly not. There are no silver bullets. And a bad process
will produce bad programs, even with the best of tools.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique oriente objet/
Beratung in objektorientierter Datenverarbeitung
9 place Smard, 78210 St.-Cyr-l'cole, France, +33 (0)1 30 23 00 34

Nov 18 '08 #83

P: n/a
On Nov 18, 6:39*pm, Juha Nieminen <nos...@thanks.invalidwrote:
James Kanze wrote:
>Garbage collection doesn't "encourage" anything.
I tend to disagree.
Sorry, but it's a statement of fact.
It might be a fact in *your* case. I disagree on it being a
fact for everybody.
There are objective facts, which do hold for everyone, whether
you like it or not. And a simple tool like garbage collection
is simply not capable of "encouraging" (or "discouraging")
anything. You're committing anthromorphism, and giving garbage
collection a power that it just doesn't have.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique oriente objet/
Beratung in objektorientierter Datenverarbeitung
9 place Smard, 78210 St.-Cyr-l'cole, France, +33 (0)1 30 23 00 34
Nov 18 '08 #84

P: n/a
On Nov 18, 9:29*pm, Hendrik Schober <spamt...@gmx.dewrote:
James Kanze wrote:
On Nov 17, 8:29 pm, Juha Nieminen <nos...@thanks.invalidwrote:
James Kanze wrote:
Sometimes I get the impression that garbage collection
actually causes people to write *less* modular and more
imperative programs. GC doesn't really encourage
encapsulation and modularity.
>Garbage collection doesn't "encourage" anything.
I tend to disagree.
Sorry, but it's a statement of fact. *Garbage collection is
just a tool; a piece of code. *It can't encourage or
discourage anything.
* OO is "just a tool", too.
OO is more than just that.
* Doesn't it encourage specific ways to program?
* (Note that I do not necessarily defend Juha's position.
* I just find yours a very weak argument.)
Yes and no. It's certain that the programming language we use
does condition us to some degree. But garbage collection isn't
a programming language, nor a paradigm. It's just a very low
level tool. As such, it isn't capable of such an effect.
(Perhap Juha is confusing this with the effects of some
programming languages that happen to use garbage collection.
But C++ with garbage collection won't become Java, nor anything
like it. It will remain very much C++.)

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique oriente objet/
Beratung in objektorientierter Datenverarbeitung
9 place Smard, 78210 St.-Cyr-l'cole, France, +33 (0)1 30 23 00 34
Nov 18 '08 #85

P: n/a
Juha Nieminen wrote:
Becomes the majority of programmers hired out there are incompetent?
Well, you have identified the core problem, all right.
A different programming language is not going to help that problem.
A different memory management mechanism is not going to make much of a
difference here but it can assist the good programmers.
Nov 18 '08 #86

P: n/a
Chris M. Thomasson wrote:
Why do you think that most of Google is written in C++?
Because.. it weighs.. as much.. as a.. duck..?
Nov 19 '08 #87

P: n/a

"Matthias Buelow" <mk*@incubus.dewrote in message
news:6o************@mid.dfncis.de...
Chris M. Thomasson wrote:
>Why do you think that most of Google is written in C++?

Because.. it weighs.. as much.. as a.. duck..?
lol!

Nov 19 '08 #88

P: n/a
On Nov 18, 7:07 am, James Kanze <james.ka...@gmail.comwrote:
On Nov 18, 5:57 am, Keith H Duggar <dug...@alum.mit.eduwrote:
On Nov 17, 4:28 am, James Kanze <james.ka...@gmail.comwrote:
On Nov 16, 11:46 pm, hurcan solter <hsol...@gmail.comwrote:
although it is not strictly necessary , it has its uses
with concurrent programming it may get really confusing
the manage the lifetime of objects when multiple threads
Attention! Garbage collection does NOT manage the lifetime
of objects. It only manages memory.
Attention! In practice the above is FALSE!

Apparently, then, you don't even know what garbage collection
does. Garbage collection manages memory. It does NOT manage
object lifetime. The two are different things (and the C++
standard very decisively keeps them separate).
I provided both the subthread and the keyword "zombie" so that
you could review some of the practical isses I'm referring to.
Did you review that thread? Or follow it at the time?
When one tries to divorce, in practical terms, the concepts of
object "lifetime" and object "storage" the can opens and
spills worms all over your language model. Since you did not
post in that recent thread I'm not sure what your solution for
"destroyed but not deallocated"
is. If you have one please post it so that Andrei and the like
can employ (or at least research) it.

It's not a recent topic, and Andrei and I have discussed it in
newsgroups in the past, and unless his position has radically
changed, we more or less agree.
It's also not a resolved topic which you implied with your
emphatic "Attention!" statement.
But I'm not sure what your question is. It's obvious that in
this case, garbage collection is necessary to protect against
and detect using dangling pointers. The idiom works because
with garbage collection, memory management is decoupled from
object lifetime; because even though the object has ceased to
exist, the memory behind it cannot be reused as long as anyone
has a pointer to it.
And what does "ceased to exist" mean? If the object does not
"exist" then what is the pointer pointing to? How about we give
the "it" (even though "it" does not "exist") that the pointer
points to a name. Hmm ... I know, let's call it a "zombie". And
there begins an entire /unresolved/ debate that you can review
in the link I provided.

Do you know of a GC system/semantics that resolves the issues
raised in that thread? Can you elaborate on its semantic model?

KHD

Nov 19 '08 #89

P: n/a

"James Kanze" <ja*********@gmail.comwrote in message
news:10**********************************@a26g2000 prf.googlegroups.com...
On Nov 18, 4:15 pm, "Chris M. Thomasson" <n...@spam.invalidwrote:
>"Matthias Buelow" <m...@incubus.dewrote in message
>news:6o************@mid.dfncis.de...
Keith H Duggar wrote:
>Yes. However, garbage collection is /only/ going to reclaim
memory, eventually. It's not going to correct the logical and
potentially far more serious design bugs that leaked memory
in the first place.
Yes, GC does not correct any bugs, you're right about that
;). However, there are many situations where having to do
manual deallocation is just additional work without any
benefit. For example, if you're doing a lot of tree
handling, building trees, throwing them away again etc., you
don't really want to traverse the tree to free all the
elements if you throw it away. Much more convenient to
simply "forget" the pointer to the tree and let automatic
memory management wipe it up.
>I would build a node cache for the trees;
In other words, extra work. That's exactly what Matthias was
arguing against.
[...]
You apparently seemed to overlook my master point:


You can create a node cache in GC environment, but it requires one to
explicitly traverse the tree and put nodes into the cache. This can indeed
reduce the number of calls to new, simply because they can be replaced with
cache hits. Efficient programming in a GC world has "some" direct
similarities to the manual world indeed.


A node cache is extra work in a GC world, and a manual world; indeed its
beneficial in both, IMVHO at least! Reduce calls to new! Cool...


Any thoughts?

:^)

Nov 19 '08 #90

P: n/a
"James Kanze" <ja*********@gmail.comwrote in message
news:1e**********************************@o40g2000 prn.googlegroups.com...
On Nov 17, 6:14 pm, "Chris M. Thomasson" <n...@spam.invalidwrote:
"James Kanze" <james.ka...@gmail.comwrote in message
news:39**********************************@w1g2000p rk.googlegroups.com...
On Nov 16, 3:54 pm, Sam <s...@email-scan.comwrote:
[...]
So they seek for a security blanket called "garbage
collection", so they don't have to worry about it, and can
proceed to churn out their spaghetti code without worry,
just like they do in Java.
That is, of course, the most obvious bullshit I've ever
seen. There are cases where garbage collection isn't
appropriate, and cases where it is necessary.
Humm.. Can you give an example or two of a scenario in which a
GC is absolutely required/necessary?
Off hand, no, but I think Hans Boehm had one.
[...]

REALLY!????? Please educate me!


AFAICT, Hans Boehm never had any concrete example which proves that GC is
required/necessary simply because said example does _not_, dare I say
CANNOT, currently exist... I have indeed engaged in fairly limited
correspondence with Hans and the *famous Paul E. McKenney on cpp-threads
standardization list about some fairly advanced non-blocking algorihtms. He
never said anything about GC being a requirement for any algorithm. Please,
try and remember where Hans mentioned anything about GC being required for
something. Please, I always want to learn new things!

:^)


* -

Thing SCO + RCU patents! Too funny!

Nov 19 '08 #91

P: n/a
On Nov 19, 6:01 am, "Chris M. Thomasson" <n...@spam.invalidwrote:
"James Kanze" <james.ka...@gmail.comwrote in message
A node cache is extra work in a GC world, and a manual world;
indeed its beneficial in both, IMVHO at least! Reduce calls to
new! Cool...
Any thoughts?
That it's an orthogonal problem. Implementing a node cache is
extra work (independantly of the memory management scheme used
otherwise). Additional cost, in other words. If the benefits
for a particular application justify the cost, you do it. If
they don't, you don't.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Nov 19 '08 #92

P: n/a
On Nov 19, 12:51 am, Matthias Buelow <m...@incubus.dewrote:
Juha Nieminen wrote:
Becomes the majority of programmers hired out there are incompetent?
Well, you have identified the core problem, all right.
I disagree, and I would take exception to such a qualification.
I've working in computerprocessing for over thirty years, most
of them as a consultant, and I've seen and worked with literally
hundreds of programmers. In all that time, I've seen only one
who could be qualified as incompetent. One of the things I've
seen in this time is that people tend to respond according to
what is expected of them. If management considers the
programmers incompetent, they will produce work that corresponds
to how management considers them. If they are treated as
intelligent and responsible persons, it is very rare that they
don't respond as such.

Also, of course, competence isn't really a boolean quantity to
begin with; there are different degrees of competence, and also
different domains (the best designer may write horrible code).
And the real problem (often classified as "programmer
incompetence") is caused by management misusing the competence
they have. (Starting with the Peter principle. If someone is a
good programmer, the first thing that happens is that he gets
promoted to a position where he will never program again.)

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Nov 19 '08 #93

P: n/a
On Nov 19, 6:11 am, "Chris M. Thomasson" <n...@spam.invalidwrote:
"James Kanze" <james.ka...@gmail.comwrote in message
news:1e**********************************@o40g2000 prn.googlegroups.com...
On Nov 17, 6:14 pm, "Chris M. Thomasson" <n...@spam.invalidwrote:
"James Kanze" <james.ka...@gmail.comwrote in message
>news:39**********************************@w1g2000 prk.googlegroups.com....
On Nov 16, 3:54 pm, Sam <s...@email-scan.comwrote:
[...]
So they seek for a security blanket called "garbage
collection", so they don't have to worry about it, and can
proceed to churn out their spaghetti code without worry,
just like they do in Java.
That is, of course, the most obvious bullshit I've ever
seen. There are cases where garbage collection isn't
appropriate, and cases where it is necessary.
Humm.. Can you give an example or two of a scenario in which a
GC is absolutely required/necessary?
Off hand, no, but I think Hans Boehm had one.
[...]
REALLY!????? Please educate me!
AFAICT, Hans Boehm never had any concrete example which proves
that GC is required/necessary simply because said example does
_not_, dare I say CANNOT, currently exist...
Actually, in discussions elsethread, I myself mentionned one
case. Robustly protecting yourself against dangling pointer
errors.
I have indeed engaged in fairly limited correspondence with
Hans and the *famous Paul E. McKenney on cpp-threads
standardization list about some fairly advanced non-blocking
algorihtms. He never said anything about GC being a
requirement for any algorithm. Please, try and remember where
Hans mentioned anything about GC being required for something.
Please, I always want to learn new things!
I forget the details, since it didn't concern anything I was
involved it. I think it had something to do with his rope
class, in cases where the memory was partially cached, or
something like that, but I'm far from certain, and I may have
misunderstood him.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Nov 19 '08 #94

P: n/a
On 2008-11-18 18:04:35 -0500, James Kanze <ja*********@gmail.comsaid:
>
Well, most garbage collectors support finalization (which is NOT
the same thing as a destructor); I'll admit, though, that I've
never really found a use for it.
I think the Java folks have come to the conclusion that finalization is
only useful for detecting failures to clean up non-memory resources. So
a class's finalizer throws an exception if the resources that the
object manages haven't been properly disposed of.

--
Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The
Standard C++ Library Extensions: a Tutorial and Reference
(www.petebecker.com/tr1book)

Nov 19 '08 #95

P: n/a
On Nov 19, 5:43 am, Keith H Duggar <dug...@alum.mit.eduwrote:
On Nov 18, 7:07 am, James Kanze <james.ka...@gmail.comwrote:
On Nov 18, 5:57 am, Keith H Duggar <dug...@alum.mit.eduwrote:
On Nov 17, 4:28 am, James Kanze <james.ka...@gmail.comwrote:
On Nov 16, 11:46 pm, hurcan solter <hsol...@gmail.comwrote:
although it is not strictly necessary , it has its uses
with concurrent programming it may get really confusing
the manage the lifetime of objects when multiple threads
Attention! Garbage collection does NOT manage the lifetime
of objects. It only manages memory.
Attention! In practice the above is FALSE!
Apparently, then, you don't even know what garbage
collection does. Garbage collection manages memory. It does
NOT manage object lifetime. The two are different things
(and the C++ standard very decisively keeps them separate).
I provided both the subthread and the keyword "zombie" so that
you could review some of the practical isses I'm referring to.
Did you review that thread? Or follow it at the time?
I might have followed it at the time; I do remember some
signification threads on this subject (in which Andrei was a
contributor). I've not had time to read the complete thread
now, however. But unless it presents some radically new
information, I'm fairly aware of the issues.
When one tries to divorce, in practical terms, the
concepts of object "lifetime" and object "storage" the can
opens and spills worms all over your language model. Since
you did not post in that recent thread I'm not sure what
your solution for
"destroyed but not deallocated"
is. If you have one please post it so that Andrei and the
like can employ (or at least research) it.
It's not a recent topic, and Andrei and I have discussed it
in newsgroups in the past, and unless his position has
radically changed, we more or less agree.
It's also not a resolved topic which you implied with your
emphatic "Attention!" statement.
I think it is, actually. At least within the context of C++;
the standard makes a very clear distinction. I'm also aware of
people raising similar issues with regards to other languages,
but I don't know how widespread the issues have been discussed
or resolved within those languages; I've had some very concrete
discussions about this concerning C#, but the person involved
(Herb Sutter) comes from a C++ background, which may have
colored his understanding.

The notion of "lifetime of an object", as described in the C++
standard, is, IMHO, fundamental to good software engineering.
Regardless of whether it is embodied in the language or not.
(As far as I know, C++ is the only language which really makes
this distinction. Although perhaps Ada... offhand, it seems
very difficult to define a constructor and even more so a
destructor without it.) One important point with regards to
garbage collection is that it doesn't affect all objects; most
objects don't need an "active" destructor. The other important
point is that some objects do, and that doing anything with such
an object after its destructor has been called (or whatever
function is used for this; in some Java circles, at least,
dispose() seems to be the preferred name) is a programming
error.
But I'm not sure what your question is. It's obvious that in
this case, garbage collection is necessary to protect
against and detect using dangling pointers. The idiom works
because with garbage collection, memory management is
decoupled from object lifetime; because even though the
object has ceased to exist, the memory behind it cannot be
reused as long as anyone has a pointer to it.
And what does "ceased to exist" mean?
That the object has been "deconstructed". That it no longer
exists as an object of type T, in the sense that it is no longer
capable of behaving as a T should, and that using it as a T is a
programming error. In classical C++, the destructor has been
called, but of course, in other languages, some other convention
may be usual.
If the object does not "exist" then what is the pointer
pointing to?
That is a good question. Nothing really. Or raw memory.
Formally (i.e. according to the C++ language definition), it
doesn't matter, since dereferencing the pointer would result in
undefined behavior. (There is a special exception here for
reading the object as an array of bytes. It don't think it's
really relevant; an array of bytes is not the object, but just
the raw memory.) In practice, of course, as we all know, if a
pointer to something exists, even if that something no longer
exists, it will be used, sooner or later.
How about we give the "it" (even though "it" does not "exist")
that the pointer points to a name. Hmm ... I know, let's call
it a "zombie". And there begins an entire /unresolved/ debate
that you can review in the link I provided.
Let's call it raw memory. That's what the C++ standard does.
And regardless of what is in that discussion (I'll try and find
time to read it, but it looks very, very long), the issue is
resolved and closed as far as C++ is concnerned. After the
destructor has been called, but before the memory has been
freed, you do not have an object. You have raw memory. (Since
you're accessing it via a T*, it is sometimes convenient to call
it a T object with a special, zombie state, but this is really
misleading.)
Do you know of a GC system/semantics that resolves the issues
raised in that thread? Can you elaborate on its semantic
model?
Well, I'll have to read the thread to be sure, but the point of
garbage collection here is that with garbage collection, the raw
memory left after the deconstruction of an object will not
(normally) change its state as long as a pointer to that memory
exists anywhere in the program. Thus, if the object was
polymorphic, the destructor can "stomp" on the memory which
contained the vptr, and any attempt to call a virtual function
is guaranteed to result in a core dump. If the memory has
already been freed, however, it may have been reallocated, and
an object may have already been constructed in it, with,
perhaps, the vptr of the new object in exactly the same place.

My personal recommendation for robustness would be to clearly
analyse, at the design phase, which objects needed
deconstruction, and which didn't, without regards to memory
management. For the latter, once design has determined that
the destructor is trivial, i.e. that the object can be logically
used as long as it is accessible, just leave it to garbage
collection. This is probably the most frequent case, but most
of the objects so designated won't ever be allocated
dynamically, either. But there will be some. For those objects
which must be deconstructed, which have a determinate lifespan,
the deconstructing function must be called at a deterministic
moment. In C++, I do this by means of the delete operator,
using the destructor as the deconstructing function; when
garbage collection is present, I replace the global operator
delete by one which overwrites the memory with some easily
identifiable pattern, which (probably) can't be a pointer to
anything valid---0xDEADBEEF is a good choice for 32 bit
machines, I think. In Java, in such cases, I simply add a
boolean variable to the base class type, which the constructor
sets true, the destructor---sorry, the dispose() function---sets
false, and I test it at the top of each function. (You'll
notice that the C++ solution is a lot less work:-).)

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Nov 19 '08 #96

P: n/a
Pete Becker wrote:
I think the Java folks have come to the conclusion that finalization is
only useful for detecting failures to clean up non-memory resources. So
a class's finalizer throws an exception if the resources that the object
manages haven't been properly disposed of.
This is an interesting result, do you have a reference for this or is it
from observation?
Nov 19 '08 #97

P: n/a
On 2008-11-19 08:53:00 -0500, Matthias Buelow <mk*@incubus.desaid:
Pete Becker wrote:
>I think the Java folks have come to the conclusion that finalization is
only useful for detecting failures to clean up non-memory resources. So
a class's finalizer throws an exception if the resources that the object
manages haven't been properly disposed of.

This is an interesting result, do you have a reference for this or is it
from observation?
No specific reference. I've seen comments to that effect, but I don't
remember where.

--
Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The
Standard C++ Library Extensions: a Tutorial and Reference
(www.petebecker.com/tr1book)

Nov 19 '08 #98

P: n/a
On 2008-11-19 09:05:45 -0500, James Kanze <ja*********@gmail.comsaid:
>
On the contrary, inexperienced developers generally don't
realize that C++ can have garbage collection.
I once read a Java article that made the assertion that C++ can't have
garbage collection because it doesn't run in a virtual machine. (This
was back in the days when every article about Java had an opening
paragraph that was a cheap shot at C++, and you had to go to the second
paragraph to find out what the article was about)

--
Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The
Standard C++ Library Extensions: a Tutorial and Reference
(www.petebecker.com/tr1book)

Nov 19 '08 #99

P: n/a
Stefan Ram wrote:
James Kanze <ja*********@gmail.comwrites:
>won't give you a saw, because you might cut yourself. C++ gives
you a chain saw, a rip saw, a band saw, and a couple of other

This reminds me of:

Like Perl, C++ is a swiss army chainsaw of a programming
language. Unlike Perl, it's got all the blades
simultaneously and permanently cast in a fixed half-open
position. Don't turn it on.
Whatever.
>
http://fare.livejournal.com/135078.html

My usual set of quotations regarding garbage collection
might be known to some readers:

There were two versions of it, one in Lisp and one in
C++. The display subsystem of the Lisp version was faster.
There were various reasons, but an important one was GC:
the C++ code copied a lot of buffers because they got
passed around in fairly complex ways, so it could be quite
difficult to know when one could be deallocated. To avoid
that problem, the C++ programmers just copied. The Lisp
was GCed, so the Lisp programmers never had to worry about
it; they just passed the buffers around, which reduced
both memory use and CPU cycles spent copying.
"Best of A is better than the worst of B...which just proves B is not as
good as A."
>
<XN*****************@newssvr13.news.prodigy.com>

A lot of us thought in the 1990s that the big battle would
be between procedural and object oriented programming, and
we thought that object oriented programming would provide
a big boost in programmer productivity. I thought that,
too. Some people still think that. It turns out we were
wrong. Object oriented programming is handy dandy, but
it's not really the productivity booster that was
promised. The real significant productivity advance we've
had in programming has been from languages which manage
memory for you automatically.
I just don't buy it. When everyone was playing around with malloc'ed
arrays by hand all over the place that may have been a valid argument.
That's been absolutely proven to be a lack of imagination on the part of
those running into this problem though for the introduction of RAII and
other idioms such as scope guarding totally destroys this argument.
>
http://www.joelonsoftware.com/articles/APIWar.html

[A]llocation in modern JVMs is far faster than the best
performing malloc implementations. The common code path
for new Object() in HotSpot 1.4.2 and later is
approximately 10 machine instructions (data provided by
Sun; see Resources), whereas the best performing malloc
implementations in C require on average between 60 and 100
instructions per call (Detlefs, et. al.; see Resources).
And allocation performance is not a trivial component of
overall performance -- benchmarks show that many
real-world C and C++ programs, such as Perl and
Ghostscript, spend 20 to 30 percent of their total
execution time in malloc and free -- far more than the
allocation and garbage collection overhead of a healthy
Java application (Zorn; see Resources).
That's nice. Luckily for us we don't have to limit ourselves to malloc
and free. Check out the book Modern C++ Design to see an implementation
of a faster allocation pool for exactly the task claimed to be Java's
advantage above. The reason why Java would perform better here is quite
clear, it's got its own memory management heap and can optimize requests
to the OS....just like anyone else can when needed in C++.
>
http://www-128.ibm.com/developerwork...vaUrbanLegends

Perhaps the most important realisation I had while developing
this critique is that high level languages are more important
to programming than object-orientation. That is, languages
which have the attribute that they remove the burden of
bookkeeping from the programmer to enhance maintainability and
flexibility are more significant than languages which just
add object-oriented features. While C++ adds object-orientation
to C, it fails in the more important attribute of being high
level. This greatly diminishes any benefits of the
object-oriented paradigm.
People that see C++ simply as an OO language are missing the entire
point. C++ is a multi-paradigm language that can be used as low or as
high as you can reach. No, it isn't a scripting language but personally
I don't think that's a bad thing. Having to query your types all the
time is NOT an advantage.
>
http://burks.brighton.ac.uk/burks/pc...t/index005.htm
Nov 19 '08 #100

158 Replies

This discussion thread is closed

Replies have been disabled for this discussion.