www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Smart pointers instead of GC?

reply "Sven Over" <dlang svenover.de> writes:
Hello dear D community.

This is my very first post here. I've been intrigued with D for 
quite a while, and I would love to have a project to work on in 
D. I'm working as a C++ software engineer, and should be 
moderately up-to-date with best practices of C++ programming.

I've read a good part of "The D Programming Language" and must 
say that I *love* almost everything about D. Metaprogramming, 
which quickly gets very convoluted in C++ (to say the least), is 
just beautiful in D. The approach to multi-threaded programming, 
and the adoption of concepts of functional programming, are all 
pure gold.

The one thing that I am unsure about in D is garbage collection. 
I guess this is some sort of FAQ and may have been answered 
dozens of times. I apologise in advance.

The main reason I dislike garbage collection for is that 
destructors of objects on the heap are not called at defined 
times. Techniques like RAII 
(http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization) 
have become an often used pattern in my programming, and works 
nicely for short lived objects (on the stack), but by means of 
smart pointers (i.e. reference counting) also for long lived 
objects (on the heap).

Also, garbage collection often tends to increase the memory 
footprint of your software. You may be able to avoid this with 
some expert knowledge about the garbage collector, but this of 
course invalidates one of the main arguments in favour of GC, 
which is less complexity. I'd say that if you want to write 
memory- and CPU-efficient code, then you'll need a certain amount 
of understanding of your memory management. Be it your manual 
memory management, or the inner workings of your garbage 
collector.

To cut things short, even after giving it a lot of thought I 
still feel uncomfortable about garbage collection. I'm wondering 
whether it is viable to use the same smart pointer techniques as 
in C++: is there an implementation already of such smart 
pointers? Can I switch off GC in my D programs altogether? How 
much does the standard library rely on GC? I.e. would I have to 
write a alternative standard library to do this?

There is one blog post I found interesting to read in this 
context, which also underlines my worries: 
http://3d.benjamin-thaut.de/?p=20
Dec 25 2012
next sibling parent "Peter Alexander" <peter.alexander.au gmail.com> writes:
On Tuesday, 25 December 2012 at 14:13:21 UTC, Sven Over wrote:
 To cut things short, even after giving it a lot of thought I 
 still feel uncomfortable about garbage collection. I'm 
 wondering whether it is viable to use the same smart pointer 
 techniques as in C++: is there an implementation already of 
 such smart pointers? Can I switch off GC in my D programs 
 altogether? How much does the standard library rely on GC? I.e. 
 would I have to write a alternative standard library to do this?

std.typecons.RefCounted!T core.memory.GC.disable(); Phobos does rely on the GC to some extent. Most algorithms and ranges do not though.
Dec 25 2012
prev sibling next sibling parent reply "Sven Over" <dlang svenover.de> writes:
 std.typecons.RefCounted!T

 core.memory.GC.disable();

Wow. That was easy. I see, D's claim of being a multi-paradigm language is not false.
 Phobos does rely on the GC to some extent. Most algorithms and 
 ranges do not though.

Running (library) code that was written with GC in mind and turning GC off doesn't sound ideal. But maybe this allows me to familiarise myself more with D. Who knows, maybe I can learn to stop worrying and love garbage collection. Thanks for your help!
Dec 25 2012
next sibling parent Benjamin Thaut <code benjamin-thaut.de> writes:
Am 31.12.2012 13:14, schrieb Sven Over:
 A smart-pointer type for arrays can easily provide slices. It keeps a
 reference to the full array (which gets destructed when the last
 reference is dropped), but addresses a subrange.

I did exactly implement this in https://github.com/Ingrater/druntime/blob/master/src/core/refcounted.d Basically I implemented a struct that mimics a regular D array as far as possible, but it is using reference counting under the hood. Kind Regards Benjamin Thaut
Dec 31 2012
prev sibling parent Benjamin Thaut <code benjamin-thaut.de> writes:
Am 31.12.2012 13:36, schrieb Sven Over:
 Hi Benjamin! I've seen your druntime and thBase repos on GitHub. Very
 interesting stuff. As I have little (or to be honest: no) experience in
 D it's difficult for me to judge how much work needs to be done. Is the
 idea to replace Phobos completely?

The idea is not to replace phobos completely. Currenly it only contains the functionality that I did need for my projects and that could not be used from phobos. std.traits, std.typetuple, and others are still used from phobos because they don't leak (or could be made non leaking with very small modifications). thBase also contains a lot of functionality phobos does not have. E.g. containers, a better xml parser/writer, templates for automiatcally serializing and deserializing objects to/from xml files and much more. Everything that I think could be usefull for other projects in the future gets added to thBase. Knid Regards Benjamin Thaut
Dec 31 2012
prev sibling next sibling parent "Leandro Lucarella" <leandro.lucarella sociomantic.com> writes:
On Tuesday, 25 December 2012 at 14:48:48 UTC, Sven Over wrote:
 Phobos does rely on the GC to some extent. Most algorithms and 
 ranges do not though.

Running (library) code that was written with GC in mind and turning GC off doesn't sound ideal.

It isn't if you care about memory leaks. And also bare in mind that some language constructs also relies on the GC, like some dynamic arrays operations (concatenation and appending for example). Right now is pretty hard to write D code that doesn't really use the GC at all.
Dec 25 2012
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Tuesday, December 25, 2012 16:33:27 Leandro Lucarella wrote:
 On Tuesday, 25 December 2012 at 14:48:48 UTC, Sven Over wrote:
 Phobos does rely on the GC to some extent. Most algorithms and
 ranges do not though.

Running (library) code that was written with GC in mind and turning GC off doesn't sound ideal.

It isn't if you care about memory leaks. And also bare in mind that some language constructs also relies on the GC, like some dynamic arrays operations (concatenation and appending for example). Right now is pretty hard to write D code that doesn't really use the GC at all.

There's also often no reason not to have the GC on and use it for certain stuff but use ref-counted objects as your main type of memory-management. Then, you avoid whatever issues the GC has in most cases but don't have to worry about what it takes to be able to not use it at all. For instance, arrays would probably be GC-allocated in general, since then you can use slices and whatnot, but maybe all of your user-defined objects on the heap could be malloced and freed with reference counts (though that sort of thing should be much easier once we have custom allocators - it's a bit more of a pain right now than it should be). - Jonathan M Davis
Dec 25 2012
prev sibling next sibling parent "Benjamin Thaut" <code benjamin-thaut.de> writes:
On Tuesday, 25 December 2012 at 19:23:59 UTC, Jonathan M Davis 
wrote:
 On Tuesday, December 25, 2012 16:33:27 Leandro Lucarella wrote:
 On Tuesday, 25 December 2012 at 14:48:48 UTC, Sven Over wrote:
 Phobos does rely on the GC to some extent. Most algorithms 
 and
 ranges do not though.

Running (library) code that was written with GC in mind and turning GC off doesn't sound ideal.

It isn't if you care about memory leaks. And also bare in mind that some language constructs also relies on the GC, like some dynamic arrays operations (concatenation and appending for example). Right now is pretty hard to write D code that doesn't really use the GC at all.

There's also often no reason not to have the GC on and use it for certain stuff but use ref-counted objects as your main type of memory-management. Then, you avoid whatever issues the GC has in most cases but don't have to worry about what it takes to be able to not use it at all. For instance, arrays would probably be GC-allocated in general, since then you can use slices and whatnot, but maybe all of your user-defined objects on the heap could be malloced and freed with reference counts (though that sort of thing should be much easier once we have custom allocators - it's a bit more of a pain right now than it should be). - Jonathan M Davis

but it is possible. Also it makes writing Code also easier ans more effektive in some places because: -You don't have to register manually allocated blocks with the gc -You control the exact order of destruction -You control the time of destruction -You control in which thread a object gets destructed -You will be encouraged to not write code that does do 100 allocations just to format a string (because it will leak) But obviously it has an impact on productivity. But I'm still more productive writing manual memory managed code in D then in C++. Kind Regards Benjamin Thaut
Dec 26 2012
prev sibling next sibling parent "Sven Over" <dlang svenover.de> writes:
On Tuesday, 25 December 2012 at 19:23:59 UTC, Jonathan M Davis 
wrote:
 There's also often no reason not to have the GC on and use it 
 for certain stuff

One thing that really freaks me out is the fact that the garbage collector pauses the whole process, i.e. all threads. In my job I'm writing backend services that power a big web site. Perfomance is key, as the response time of the data service in most cases directly adds to the page load time. The bare possibility that the whole service pauses for, say, 100ms is making me feel very uncomfortable. We easily achieve the performance and reliability we need in C++, but I would love to give D a chance, as it solves many inconveniences of C++ in an elegant way. Metaprogramming and the threading model, just to name two.
 For instance, arrays would probably be GC-allocated in general, 
 since
 then you can use slices and whatnot,

A smart-pointer type for arrays can easily provide slices. It keeps a reference to the full array (which gets destructed when the last reference is dropped), but addresses a subrange. Thanks everyone for all the replies!
Dec 31 2012
prev sibling next sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Monday, 31 December 2012 at 12:14:22 UTC, Sven Over wrote:
 On Tuesday, 25 December 2012 at 19:23:59 UTC, Jonathan M Davis 
 wrote:
 There's also often no reason not to have the GC on and use it 
 for certain stuff

One thing that really freaks me out is the fact that the garbage collector pauses the whole process, i.e. all threads. In my job I'm writing backend services that power a big web site. Perfomance is key, as the response time of the data service in most cases directly adds to the page load time. The bare possibility that the whole service pauses for, say, 100ms is making me feel very uncomfortable. We easily achieve the performance and reliability we need in C++, but I would love to give D a chance, as it solves many inconveniences of C++ in an elegant way. Metaprogramming and the threading model, just to name two.
 For instance, arrays would probably be GC-allocated in 
 general, since
 then you can use slices and whatnot,

A smart-pointer type for arrays can easily provide slices. It keeps a reference to the full array (which gets destructed when the last reference is dropped), but addresses a subrange. Thanks everyone for all the replies!

I think the problem would be if you try to append to the slice (~): If the underlying array is not GC allocated, then it will append to a new GC allocated array (AFAIK). As long as you don't append, I'd say you are fine.
Dec 31 2012
prev sibling next sibling parent "Sven Over" <dlang svenover.de> writes:
On Wednesday, 26 December 2012 at 11:43:55 UTC, Benjamin Thaut 
wrote:
 In my experience its quite some work to remove the GC entierly, 
 but it is possible.

Hi Benjamin! I've seen your druntime and thBase repos on GitHub. Very interesting stuff. As I have little (or to be honest: no) experience in D it's difficult for me to judge how much work needs to be done. Is the idea to replace Phobos completely?
 Also it makes writing Code also easier ans more effektive in 
 some places
 because:
 -You don't have to register manually allocated blocks with the 
 gc
 -You control the exact order of destruction
 -You control the time of destruction
 -You control in which thread a object gets destructed
 -You will be encouraged to not write code that does do 100 
 allocations just to format a string (because it will leak)

I personally agree with all your points, but I must admit that their relevance depends on the programming patterns you are using. Experienced GC programmers certainly favour patterns that work well with GC. I personally prefer a style of programming that makes use of destructors and relies on them being executed at the right time.
 But obviously it has an impact on productivity.

I'm not sure about this at all. I write software that is designed to offer a certain performance, and latency is a big issue. I don't believe that I can achieve that with a "just allocate memory and don't ever care" attitude. I would need some background knowledge about how the GC works, and write code that doesn't screw up badly. Manual memory management also requires me to have an understanding of the implications behind it. But there are well-tested helpers (e.g. smart pointers) that simplify the task a lot. I do admit that, when performance (both in the sense of being fast and offering reliable performance) is not such a critical issue, then GC won't hurt and "just allocating" is fine and of course reduces development time. However, I tend to just use Python for this class problems. It comes down to a matter of choice and personal preference. I'm not saying that GC is bad and shouldn't be used. Many people are very happy with it and it does a great job for them. But my personal preference is manual memory management (then again greatly automated by use of reference counting and smart pointers).
Dec 31 2012
prev sibling next sibling parent "Sven Over" <dlang svenover.de> writes:
On Monday, 31 December 2012 at 12:36:06 UTC, monarch_dodra wrote:
 On Monday, 31 December 2012 at 12:14:22 UTC, Sven Over wrote:

 A smart-pointer type for arrays can easily provide slices. It 
 keeps a reference to the full array (which gets destructed 
 when the last reference is dropped), but addresses a subrange.


 I think the problem would be if you try to append to the slice 
 (~): If the underlying array is not GC allocated, then it will 
 append to a new GC allocated array (AFAIK).

 As long as you don't append, I'd say you are fine.

Of course your smart-array-pointer type needs to implement the ~ operator and create a copy of the array in that case. I guess the full implementation would include something that would resemble that of std::vector in C++. I should get started writing those types. Then I could either demonstrate that it does work, or understand that it doesn't (and why).
Dec 31 2012
prev sibling next sibling parent "jerro" <a a.com> writes:
 Of course your smart-array-pointer type needs to implement the 
 ~ operator and create a copy of the array in that case. I guess 
 the full implementation would include something that would 
 resemble that of std::vector in C++.

std.container.Array already does that.
Dec 31 2012
prev sibling next sibling parent "Kiith-Sa" <kiithsacmp gmail.com> writes:
I think you're overthinking this way too much.

I'm writing a game engine, where latency is much more important
than in your case. Even 10ms would translate to visible jitter.
GC's not an issue, and disabling it permanently is very
counterproductive _unless_ you've exhausted all other options
(which you're unlikely to, as you can do everything you can do in
C++).  All you have to do is care about how you allocate and, if
GC seems to be an issue, profile to see _where_ the GC is being
called most and optimize those allocations.

Basic rules:

For classes with one or few instances (singletons, etc.), GC is
not an issue. For classes with hundreds-thousands of instances,
it might be an issue. Profile. For classes with more instances,
it probably is an issue. Profile, reuse instances, use structs,
manually allocate.  Arrays: To avoid reallocation on append, use
array.assumeSafeAppend() before the append (Assumes that the
array is not a slice of a bigger array that would get its data
overwritten).

If appending a lot, use std.array.Appender. If you need manually
allocated storage, use std.container.Array, or create a wrapper
around malloc/free. I'm using a templated wrapper that allows me
to record how much memory/instances was allocated with which
types.  Destructors: Structs are RAII like in C. And you can
easily create a malloc wrapper that will act exactly like
new/delete in C++.

Classes: call destroy(instance). Calls the dtor, but doesn't
deallocate the class (GC will do that later). Not much different
from deleting a class allocated through new in C++ (which is what
you do most of the time in C++).  If you absolutely need to free
the memory, create malloc/free wrappers for classes.  In my case,
classes are used for polymorphic stuff, which are usually single
or few-instance objects. Structs are used for most of the
many-instance objects (e.g. components of game entities), and are
usually stored in manually allocated arrays.

GC is _very_ useful for stuff like closures, which can greatly
simplify some code. Also, while I maintain that disabling GC
completely is a bad idea, it might be useful to disable it in a
small area of code _after_ profiling shows that GC is being
called too much there.

In my YAML parser library, I've found after profiling that 18% of
time was spent in GC. Most of that was in a small piece of code
that repeatedly allocated memory. Disabling GC before this code
and reenabling it after (scope(exit) to avoid leaking disabled
GC) resulted in GC taking ~2% of time, because many unnecessary
collects were consolidated into one after the GC was reenabled.
Memory usage didn't take a hit, because this was actually a
fairly small piece of code, not doing too many allocations per
call, just called very often.
Dec 31 2012
prev sibling next sibling parent "pjmlp" <pjmlp progtools.org> writes:
On Monday, 31 December 2012 at 14:05:01 UTC, Kiith-Sa wrote:
 I think you're overthinking this way too much.

 I'm writing a game engine, where latency is much more important
 than in your case. Even 10ms would translate to visible jitter.
 GC's not an issue, and disabling it permanently is very
 counterproductive _unless_ you've exhausted all other options
 (which you're unlikely to, as you can do everything you can do 
 in
 C++).  All you have to do is care about how you allocate and, if
 GC seems to be an issue, profile to see _where_ the GC is being
 called most and optimize those allocations.

 Basic rules:

 For classes with one or few instances (singletons, etc.), GC is
 not an issue. For classes with hundreds-thousands of instances,
 it might be an issue. Profile. For classes with more instances,
 it probably is an issue. Profile, reuse instances, use structs,
 manually allocate.  Arrays: To avoid reallocation on append, use
 array.assumeSafeAppend() before the append (Assumes that the
 array is not a slice of a bigger array that would get its data
 overwritten).

 If appending a lot, use std.array.Appender. If you need manually
 allocated storage, use std.container.Array, or create a wrapper
 around malloc/free. I'm using a templated wrapper that allows me
 to record how much memory/instances was allocated with which
 types.  Destructors: Structs are RAII like in C. And you can
 easily create a malloc wrapper that will act exactly like
 new/delete in C++.

 Classes: call destroy(instance). Calls the dtor, but doesn't
 deallocate the class (GC will do that later). Not much different
 from deleting a class allocated through new in C++ (which is 
 what
 you do most of the time in C++).  If you absolutely need to free
 the memory, create malloc/free wrappers for classes.  In my 
 case,
 classes are used for polymorphic stuff, which are usually single
 or few-instance objects. Structs are used for most of the
 many-instance objects (e.g. components of game entities), and 
 are
 usually stored in manually allocated arrays.

 GC is _very_ useful for stuff like closures, which can greatly
 simplify some code. Also, while I maintain that disabling GC
 completely is a bad idea, it might be useful to disable it in a
 small area of code _after_ profiling shows that GC is being
 called too much there.

 In my YAML parser library, I've found after profiling that 18% 
 of
 time was spent in GC. Most of that was in a small piece of code
 that repeatedly allocated memory. Disabling GC before this code
 and reenabling it after (scope(exit) to avoid leaking disabled
 GC) resulted in GC taking ~2% of time, because many unnecessary
 collects were consolidated into one after the GC was reenabled.
 Memory usage didn't take a hit, because this was actually a
 fairly small piece of code, not doing too many allocations per
 call, just called very often.

I think it will still take a few generations of programmers until everyone is confortable with using GC enabled languages for systems programming scenarios. Most people nowadays are not aware of what has already been done in academia, or are burned by bad experiences caused by whatever reasons. This situation will only improve when developers start aproaching the same class of problems with open minds on how to solve them in new ways. -- Paulo
Dec 31 2012
prev sibling next sibling parent Stewart Gordon <smjg_1998 yahoo.com> writes:
On 25/12/2012 14:13, Sven Over wrote:
<snip>
 Also, garbage collection often tends to increase the memory footprint of
 your software.

ISTM you can't really make a like-for-like comparison, since non-GC programs vary a lot in how much they leak memory, which becomes almost a non-issue when you have GC. I say "almost" because GC systems often aren't perfect. For instance, a GC might mistake some sequence of four or eight bytes for a pointer and keep hold of the allocated memory it is pointing to. Java has been known to leak memory in certain circumstances, such as not disposing a window when you've finished with it, or creating a thread but never starting it. But there is something called packratting, which is a mistake at the code level of keeping a pointer hanging around for longer than necessary and therefore preventing whatever it's pointing to from being GC'd.
 You may be able to avoid this with some expert knowledge
 about the garbage collector, but this of course invalidates one of the
 main arguments in favour of GC, which is less complexity. I'd say that
 if you want to write memory- and CPU-efficient code, then you'll need a
 certain amount of understanding of your memory management. Be it your
 manual memory management, or the inner workings of your garbage collector.

 To cut things short, even after giving it a lot of thought I still feel
 uncomfortable about garbage collection.

That means you're uncomfortable about reference-counted smart pointers, because these are a form of garbage collection. :)
 I'm wondering whether it is
 viable to use the same smart pointer techniques as in C++: is there an
 implementation already of such smart pointers? Can I switch off GC in my
 D programs altogether? How much does the standard library rely on GC?
 I.e. would I have to write a alternative standard library to do this?

Good luck at getting your alternative library accepted as part of the D standard. :) Seriously though, it's as much built-in language functionality as the standard library that relies on GC. Any of the following will allocate memory from the GC heap: - create anything with the 'new' keyword - increase the length of a dynamic array - concatenate arrays - duplicate an array with .dup or .idup - put data into an associative array Which means sooner or later the garbage will need to be collected, unless the program is such that all memory allocation will be done at startup and then released only on exit. Of course, whether the program can reasonably be written in this way depends on the nature of the program.
 There is one blog post I found interesting to read in this context,
 which also underlines my worries: http://3d.benjamin-thaut.de/?p=20

An interesting set of observations. Looking at this one: "Calls to the druntime invariant handler are emitted in release build also and there is no way to turn them off. Even if the class does not have any invariants the invariant handler will always be called, walk the class hirarchy and generate multiple cache misses without actually doing anything." There seem to be two bugs here: that these calls are generated even in release mode, and that they are generated even if the class has no invariants. One of us needs to experiment with this a bit more and get these issues filed in Bugzilla. Stewart.
Jan 01 2013
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Monday, December 31, 2012 15:05:00 Kiith-Sa wrote:
 I think you're overthinking this way too much.
 
 I'm writing a game engine, where latency is much more important
 than in your case. Even 10ms would translate to visible jitter.
 GC's not an issue, and disabling it permanently is very
 counterproductive _unless_ you've exhausted all other options
 (which you're unlikely to, as you can do everything you can do in
 C++).  All you have to do is care about how you allocate and, if
 GC seems to be an issue, profile to see _where_ the GC is being
 called most and optimize those allocations.
 
 Basic rules:

If you've got this much figured out with reasonably clear guidelines, you should consider writing a blog post or article about it. - Jonathan M Davis
Jan 01 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Monday, 31 December 2012 at 12:14:22 UTC, Sven Over wrote:
 On Tuesday, 25 December 2012 at 19:23:59 UTC, Jonathan M Davis 
 wrote:
 There's also often no reason not to have the GC on and use it 
 for certain stuff

One thing that really freaks me out is the fact that the garbage collector pauses the whole process, i.e. all threads. In my job I'm writing backend services that power a big web site. Perfomance is key, as the response time of the data service in most cases directly adds to the page load time. The bare possibility that the whole service pauses for, say, 100ms is making me feel very uncomfortable.

I understand that. However, refcounted stuff tends to die in cluster as well and create pauses. The main issue here is clearly GC's implementation rather than the concept of GC in itself (which can be quite good at avoiding pauses if you are ready to make some other tradeoffs).
 We easily achieve the performance and reliability we need in 
 C++, but I would love to give D a chance, as it solves many 
 inconveniences of C++ in an elegant way. Metaprogramming and 
 the threading model, just to name two.

Here is something I tried in the past with some success : use RefCounted and GC.free . Doing so, you allocate in the GC heap, but you will limit greatly the amount of garbage that the GC have to collect by itself. Note that in some cases, GC means greater performances (usually when associated with immutability), so disabling it entirely don't seems a good idea to me.
Jan 01 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Monday, 31 December 2012 at 14:43:27 UTC, pjmlp wrote:
 I think it will still take a few generations of programmers 
 until everyone is confortable with using GC enabled languages 
 for systems programming scenarios.

 Most people nowadays are not aware of what has already been 
 done in academia, or are burned by bad experiences caused by 
 whatever reasons.

 This situation will only improve when developers start 
 aproaching the same class of problems with open minds on how to 
 solve them in new ways.

 --
 Paulo

D's GC has some implementation issue as well.
Jan 01 2013
prev sibling next sibling parent "DythroposTheImposter" <barf barf.com> writes:
  I'm interested in how the new LuaJIT GC ends up performing. But 
overall I can't say I have much hope for GC right now.

  GC/D = Generally Faster allocation. Has a cost associated with 
every living object.

  C++ = Generally Slower allocation, but while it is alive there 
is no cost.

  So as the heap grows, the GC language falls behind.

  This seems to be the case in every language I've looked at this 
uses a GC.
Jan 02 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Wednesday, 2 January 2013 at 11:41:33 UTC, 
DythroposTheImposter wrote:
  I'm interested in how the new LuaJIT GC ends up performing. 
 But overall I can't say I have much hope for GC right now.

  GC/D = Generally Faster allocation. Has a cost associated with 
 every living object.

True, however, GC + immutability allow new idoms that are plain impossible in a non GC world, and that are really efficients at reducing copies and allocations (and used in many high perf D libs). The comparison you present here fail to take this into account.
  C++ = Generally Slower allocation, but while it is alive there 
 is no cost.

Counting reference have a cost. Plus, when the heap grow, the object that dies together tend to grow as well, which cause pauses. Latency contrived programs, like video games, tends to avoid allocation altogether because of this. This obviously work both with GC and reference counting.
  So as the heap grows, the GC language falls behind.

That is more subtle than that. Reconsider what I wrote above, for instance that GC + immutability can be used to reduce allocations (so live heap size). You'll also have to consider that GC can be concurrent, when reference counting usually cannot (or loose some of its benefit compared to GC).
  This seems to be the case in every language I've looked at 
 this uses a GC.

Most GC language lack proper memory management, and sometime have design choice that are a nightmare for the GC (java have no value type for instance). You are comparing here way more than simply GC vs other memory management. Considering the pro and cons of each, an hybrid approach seems like the most reasonable thing to do in any high performance program. Which is possible in D because of GC.free .
Jan 02 2013
prev sibling next sibling parent "Thiez" <thiezz gmail.com> writes:
On Wednesday, 2 January 2013 at 12:32:01 UTC, deadalnix wrote:
 Most GC language lack proper memory management, and sometime 
 have design choice that are a nightmare for the GC (java have 
 no value type for instance).

Surely Java's primitive types (byte, short, int, long, float, double, boolean, and char) count as value types?
Jan 02 2013
prev sibling next sibling parent "Mehrdad" <wfunction hotmail.com> writes:
On Tuesday, 1 January 2013 at 16:31:55 UTC, Stewart Gordon wrote:
 But there is something called packratting, which is a mistake 
 at the code level of keeping a pointer hanging around for 
 longer than necessary and therefore preventing whatever it's 
 pointing to from being GC'd.

I've heard it called "midlife crisis" :)
Jan 02 2013
prev sibling next sibling parent "Mehrdad" <wfunction hotmail.com> writes:
On Wednesday, 2 January 2013 at 17:18:52 UTC, Thiez wrote:
 On Wednesday, 2 January 2013 at 12:32:01 UTC, deadalnix wrote:
 Most GC language lack proper memory management, and sometime 
 have design choice that are a nightmare for the GC (java have 
 no value type for instance).

Surely Java's primitive types (byte, short, int, long, float, double, boolean, and char) count as value types?

I think he meant non-primitives
Jan 02 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Wednesday, 2 January 2013 at 17:18:52 UTC, Thiez wrote:
 On Wednesday, 2 January 2013 at 12:32:01 UTC, deadalnix wrote:
 Most GC language lack proper memory management, and sometime 
 have design choice that are a nightmare for the GC (java have 
 no value type for instance).

Surely Java's primitive types (byte, short, int, long, float, double, boolean, and char) count as value types?

Yes, but they are irrelevant for the GC.
Jan 02 2013
prev sibling parent "pjmlp" <pjmlp progtools.org> writes:
On Wednesday, 2 January 2013 at 11:41:33 UTC, 
DythroposTheImposter wrote:
  I'm interested in how the new LuaJIT GC ends up performing. 
 But overall I can't say I have much hope for GC right now.

  GC/D = Generally Faster allocation. Has a cost associated with 
 every living object.

  C++ = Generally Slower allocation, but while it is alive there 
 is no cost.

  So as the heap grows, the GC language falls behind.

  This seems to be the case in every language I've looked at 
 this uses a GC.

As a former user from Native Oberon and BlueBottle OS back in the late 90's, I can attest that the GC was fast enough for powering a single user desktop operating system. Surely there are cases where it is an issue, mainly due to hardware constraints. While I am a GC supporter, I wouldn't like to fly in an airplane with a GC system, but a few missile radar systems are controled with GC based systems (Ground Master 400). So who knows?! -- Paulo
Jan 02 2013