Do you use a garbage collector?

Discussion in 'C++' started by Lloyd Bonafide, Apr 10, 2008.

  1. I followed a link to James Kanze's web site in another thread and was
    surprised to read this comment by a link to a GC:

    "I can't imagine writing C++ without it"

    How many of you c.l.c++'ers use one, and in what percentage of your
    projects is one used? I have never used one in personal or professional
    C++ programming. Am I a holdover to days gone by?
    Lloyd Bonafide, Apr 10, 2008
    #1
    1. Advertising

  2. Lloyd Bonafide

    Daniel Kraft Guest

    Lloyd Bonafide wrote:
    > I followed a link to James Kanze's web site in another thread and was
    > surprised to read this comment by a link to a GC:
    >
    > "I can't imagine writing C++ without it"
    >
    > How many of you c.l.c++'ers use one, and in what percentage of your
    > projects is one used? I have never used one in personal or professional
    > C++ programming. Am I a holdover to days gone by?


    I can't tell what professional C++ programming is about or similar, but
    I've also never used a GC for any of my projects (and those included
    ones with several months of development time and non-trivial structure).

    I've never seen the need for it and in fact am rather happy if I can do
    the memory management explicitelly rather than by a GC which feels
    cleaner to me (BTW, I also only once needed to do reference-counting, so
    for those things the "refcounting requires more time than GC"-argument
    is out).

    Daniel

    --
    Done: Bar-Sam-Val-Wiz, Dwa-Elf-Hum-Orc, Cha-Law, Fem-Mal
    Underway: Ran-Gno-Neu-Fem
    To go: Arc-Cav-Hea-Kni-Mon-Pri-Rog-Tou
    Daniel Kraft, Apr 10, 2008
    #2
    1. Advertising

  3. Lloyd Bonafide wrote:
    > How many of you c.l.c++'ers use one, and in what percentage of your
    > projects is one used? I have never used one in personal or professional
    > C++ programming. Am I a holdover to days gone by?


    I have never used a GC for C++, yet in none of my C++ projects
    (professional or hobby) in the last 5+ years have I had a memory leak. I
    often use tools such as valgrind and AQTime to check for memory leaks,
    and they have yet to report any leak.

    There just exists a *style* of programming in C++ which very naturally
    leads to encapsulated, clean and safe code. (This style is drastically
    different from how, for example, Java programming is usually done.)

    One situation where GC *might* help a bit is in efficiency if you are
    constantly allocating and deallocating huge amounts of small objects in
    tight loops. 'new' and 'delete' in C++ are rather slow operations, and a
    well-designed GC might speed things up.
    However, part of my C++ programming style just naturally also avoids
    doing tons of news and deletes in tight loops (which is, again, very
    different from eg. Java programming where you basically have no choice).
    Thus this has never been a problem in practice.

    Even if I some day stumble across a situation where constant
    allocations and deallocations are impacting negatively the speed of a
    program, and there just isn't a way around it, I can use a more
    efficient allocator than the default one used by the compiler. (I have
    measured speedups to up to over 8 times when using an efficient
    allocator compared to the default one.)
    Juha Nieminen, Apr 10, 2008
    #3
  4. Juha Nieminen <> writes:

    > Lloyd Bonafide wrote:
    >> How many of you c.l.c++'ers use one, and in what percentage of your
    >> projects is one used? I have never used one in personal or professional
    >> C++ programming. Am I a holdover to days gone by?

    >
    > I have never used a GC for C++, yet in none of my C++ projects
    > (professional or hobby) in the last 5+ years have I had a memory leak. I
    > often use tools such as valgrind and AQTime to check for memory leaks,
    > and they have yet to report any leak.
    >
    > There just exists a *style* of programming in C++ which very naturally
    > leads to encapsulated, clean and safe code. (This style is drastically
    > different from how, for example, Java programming is usually done.)
    >
    > One situation where GC *might* help a bit is in efficiency if you are
    > constantly allocating and deallocating huge amounts of small objects in
    > tight loops. 'new' and 'delete' in C++ are rather slow operations, and a
    > well-designed GC might speed things up.
    > However, part of my C++ programming style just naturally also avoids
    > doing tons of news and deletes in tight loops (which is, again, very
    > different from eg. Java programming where you basically have no choice).
    > Thus this has never been a problem in practice.
    >
    > Even if I some day stumble across a situation where constant
    > allocations and deallocations are impacting negatively the speed of a
    > program, and there just isn't a way around it, I can use a more
    > efficient allocator than the default one used by the compiler. (I have
    > measured speedups to up to over 8 times when using an efficient
    > allocator compared to the default one.)


    Now, on another level, I'd say that the problem is that this safe
    style you must adopt in C++ to avoid memory leaks is a burden that
    forces you to spend your energy in a sterile direction.

    More dynamic languages, with a garbage collector, are liberating your
    mind, so your free neurons can now think about more interesting
    software problems (like for example, AI, or providing a better user
    experience, etc).


    --
    __Pascal Bourguignon__
    Pascal J. Bourguignon, Apr 10, 2008
    #4
  5. Lloyd Bonafide

    Noah Roberts Guest

    Lloyd Bonafide wrote:
    > I followed a link to James Kanze's web site in another thread and was
    > surprised to read this comment by a link to a GC:
    >
    > "I can't imagine writing C++ without it"
    >
    > How many of you c.l.c++'ers use one, and in what percentage of your
    > projects is one used? I have never used one in personal or professional
    > C++ programming. Am I a holdover to days gone by?


    I use RAII. I've had memory leaks but it's usually due to some third
    party application I didn't understand adequately. I was never able to
    figure out why AQTime was reporting large chunks of memory loss in my
    use of the sqlite3 library for example. We abandoned its use.
    Noah Roberts, Apr 10, 2008
    #5
  6. Pascal J. Bourguignon wrote:

    > More dynamic languages, with a garbage collector, are liberating your
    > mind, so your free neurons can now think about more interesting
    > software problems (like for example, AI, or providing a better user
    > experience, etc).


    Hey now, what's this nonsense against the pure joy if your program looks
    totally cryptic, proves that you know the fine details of an 800 pages
    thick standard, and runs an infinite loop in under 3 seconds...
    Matthias Buelow, Apr 10, 2008
    #6
  7. Lloyd Bonafide

    Guest

    On Apr 10, 10:03 am, (Pascal J. Bourguignon)
    wrote:

    > More dynamic languages, with a garbage collector, are liberating your
    > mind, so your free neurons can now think about more interesting
    > software problems (like for example, AI, or providing a better user
    > experience, etc).


    You still have to worry about leaking memory (and dereferencing null
    pointers) in languages like Java.

    http://www.ibm.com/developerworks/library/j-leaks/index.html
    , Apr 10, 2008
    #7
  8. Pascal J. Bourguignon wrote:
    > Now, on another level, I'd say that the problem is that this safe
    > style you must adopt in C++ to avoid memory leaks is a burden that
    > forces you to spend your energy in a sterile direction.


    I strongly disagree. This style of programming almost automatically
    leads to a clean, abstract, encapsulated design, which is only a good thing.

    Programmers using languages with GC (such as Java) might not need to
    worry about where their dynamically-allocated memory is going, but
    neither do I, in most cases. I even dare to claim that at least in some
    cases this style of modular programming produces cleaner, simpler, more
    understandable and in some cases even more efficient code than a
    "mindlessly use 'new' everywhere" style of programming.

    I honestly don't feel that I need to put any extra effort to produce
    this kind of safe and clean code. Given that I usually like the end
    result as a design, even if I have to put that bit of extra effort it's
    totally worth it.

    > More dynamic languages, with a garbage collector, are liberating your
    > mind, so your free neurons can now think about more interesting
    > software problems (like for example, AI, or providing a better user
    > experience, etc).


    I have my doubts that this "liberating" style of programming somehow
    automatically leads to clean, modular and abstract designs. All the
    contrary, I would even claim that at least in some cases it leads to the
    opposite direction ("reckless programming").
    Juha Nieminen, Apr 10, 2008
    #8
  9. Razii wrote:
    > In C++, each "new" allocation request
    > will be sent to the operating system, which is slow.


    That's blatantly false.

    At least with the memory allocation logic in linux's libc (and I guess
    in most other unix systems as well) the only system call that is made is
    brk(), which increments the size of the heap. AFAIK this is done in
    relatively large chunks to avoid every minuscule 'new' causing a brk()
    call. Thus the OS is called relatively rarely. The actual memory
    allocation of the blocks allocated with 'new' (or 'malloc') are done by
    the routine in libc, not by the OS.

    I don't know how Windows compilers do it, but I bet it's something
    very similar to this.

    I don't see how this is so much different from what Java does.
    Juha Nieminen, Apr 11, 2008
    #9
  10. Lloyd Bonafide

    Jerry Coffin Guest

    In article <>,
    says...
    > On Thu, 10 Apr 2008 17:33:21 +0300, Juha Nieminen
    > <> wrote:
    >
    > > However, part of my C++ programming style just naturally also avoids
    > >doing tons of news and deletes in tight loops (which is, again, very
    > >different from eg. Java programming where you basically have no choice)

    >
    > Howeever, Java allocates new memory blocks on it's internal heap
    > (which is allocated in huge chunks from the OS). In this way, in most
    > of the cases it bypasses memory allocation mechanisms of the
    > underlying OS and is very fast. In C++, each "new" allocation request
    > will be sent to the operating system, which is slow.


    I know of one library implementation for which this was true (one of the
    first 32-bit versions of Visual C++), but it's generally false. Even in
    that version of that compiler, the library _contained_ code to allocate
    from the OS in large blocks, and then do sub-allocations out of that
    block. For reasons known only to Microsoft, that code was disabled by
    default.

    There is still typically some difference in speed, at least when a
    compacting GC is used. Specifically, since this keeps the free memory in
    the heap in one large chunk, allocation is done about like on a stack.

    By contrast, with a manually managed heap that doesn't do compaction,
    you end up with free blocks interspersed with blocks in use. In a really
    traditional design, the allocator might round the requested size up to
    the next multiple of, say, 16 bytes, and then walk through the list of
    free blocks to find one large enough to satisfy the request. When it
    found one, it would check the current size of the block, and if it
    exceeded the requested size by at least some margin, it would split the
    block in two, satisfying the request with one and placing the other back
    on the free list.

    More recent designs do things like rounding requests to powers of two
    (starting from 16 or so), and keeping a separate free list for each
    size. Once you've rounded up the size, you search in the correct list,
    and either a block is there, or it isn't. If it isn't, you go to the
    next larger block size, split that block in half, satisfy the request
    with one half, and place the other half on the previously-empty free
    list for its new size.

    The former version can be quite slow, especially if there are a lot of
    free blocks in the system. As you can probably guess, the latter can
    improve speed quite a bit.

    --
    Later,
    Jerry.

    The universe is a figment of its own imagination.
    Jerry Coffin, Apr 11, 2008
    #10
  11. Lloyd Bonafide

    Arne Vajhøj Guest

    Re: Do you use a garbage collector (java vs c++ difference in "new")

    Razii wrote:
    > Let's test this about the keyword "new" and tight loops. Because in
    > most cases Java allocates new memory blocks on it's internal heap and
    > bypasses memory allocation mechanisms of the underlying OS, the
    > keyword "new" doesn't mean the same thing that it does in C++, where
    > each "new" allocation request is sent to the operating system, which
    > is very slow.


    I can not imagine any C++ runtime that makes an operating system
    call for each new.

    The runtime allocates huge chunks from the OS and then manage
    it internally.

    Arne
    Arne Vajhøj, Apr 11, 2008
    #11
  12. Re: Do you use a garbage collector (java vs c++ difference in "new")

    "Razii" <> wrote in message
    news:...
    > On Thu, 10 Apr 2008 21:43:45 -0400, Arne Vajhøj <>
    > wrote:
    >
    >>I can not imagine any C++ runtime that makes an operating system
    >>call for each new.
    >>
    >>The runtime allocates huge chunks from the OS and then manage
    >>it internally.

    >
    > Testing the keyword "new"
    >
    > Time: 2125 ms (C++)
    > Time: 328 ms (java)
    >
    > Explain that.


    The C++ allocator is less efficient. There's a big difference between that
    and "makes an OS call for each allocation". In fact, given how highly
    optimized Java allocators are these days, the fact that C++ is taking less
    than 7 times as long proves that it's *not* making an OS call.
    Mike Schilling, Apr 11, 2008
    #12
  13. Lloyd Bonafide

    Jerry Coffin Guest

    In article <>,
    says...

    [ ... ]

    > You are incorrect. Each call into "new" will "most-likely" be "fast-pathed"
    > into a "local" cache. On multi-threaded systems, this "cache-hit" can even
    > be accomplished without using _any_ interlocked RMW or memory barrier
    > instruction(s). That is, the cache would be per-thread. Some may think that
    > if a cache is per-thread then a thread will not be able to free something
    > unless it allocated it. This is false line of thinking. There are different
    > algorithms that can solve this, one of them can be found here:
    >
    > http://groups.google.com/group/comp.arch/browse_frm/thread/24c40d42a04ee855
    >
    > Hoard and StreamFlow also use per-thread heaps.


    Most of the problem seems to be that people think in terms of a heap
    having a single free list, so all other threads have to contend for
    access to that free list.

    A trivially simple design is for each thread to have its own heap, and
    each heap to have one free list for every other thread in the system.
    Each other thread can then free blocks to any heap with minimal
    possibility of contention (specifically, with the thread whose heap it's
    freeing memory TO, and then only if it happens while that thread is
    grabbing that free list to coalesce its memory with the other free
    blocks.

    This contention can normally be reduced to a single atomic exchange to
    free memory and another to grab memory for coalescing. Specifically,
    consider a structure something like:

    struct free_block {
    void *next;
    size_t size;
    size_t origin_threadID;
    char payload[0];
    };

    Technically, that's not legal in C++, but I supect you get the idea.
    Let's also assume each thread's heap has a vector of free-lists,
    something like:

    typedef std:vector<free_block *> free_list;

    And we have a vector of free lists, one per thread:

    std::vector<free_list> free_lists;

    In that case, freeing a block looks something like:

    void free_a_block(void *block) {
    free_block *f = ((char *)block)-sizeof(free_block);
    f->next = f;
    size_t heap = f->origin_threadID;
    size_t my_threadID = get_current_thread_ID();

    atomic_exchange(f->next, free_lists[heap][my_thread_ID]);
    }

    I.e. we put this block's address into its own 'next' field, and then
    exchange that with the pointer to the head of our free list in the
    appropriate heap.

    If you want to eliminate even the last vestige of a wait, you can go one
    step further: have each free list contain _two_ free-list heads instead
    of one. At any given time, the owning thread may be using only one of
    those. You use a mutex that waits on both, and one of them will always
    be free. You update it, and free the mutex. The design isn't lock free,
    but it guarantees that you'll never have to wait for the lock to take
    place -- both mutexes will be free most of the time, but at least one
    will be all the time. The wait for the mutex just determines _which_ one
    is free right now.

    Of course, in reality that design is generally overkill -- the chances
    that all threads will be freeing memory on a single thread's heap at any
    given time is minmal to say the least. If we don't mind introducing the
    possibility of some waiting, it's pretty trivial to automatically
    balance between speed and memory usage -- we start with a single free
    list in each heap (and a mutex associated with each free list).

    When we want to free a block, we wait on the set of mutexes for a heap,
    with a fairly short timeout. If the wait succeeds, we free the memory
    and go on our way. If the wait fails, we signal the thread that a wait
    failed. After waits fail some number of times, the thread reacts by
    increasing the number of available free lists. Both the length of the
    wait and the number of failures can be adjusted to balance between
    performance and memory usage.

    --
    Later,
    Jerry.

    The universe is a figment of its own imagination.
    Jerry Coffin, Apr 11, 2008
    #13
  14. Lloyd Bonafide

    Jerry Coffin Guest

    In article <Xns9A7C46D97C8lbonafideyahoocom@194.177.96.26>,
    says...
    > I followed a link to James Kanze's web site in another thread and was
    > surprised to read this comment by a link to a GC:
    >
    > "I can't imagine writing C++ without it"
    >
    > How many of you c.l.c++'ers use one, and in what percentage of your
    > projects is one used? I have never used one in personal or professional
    > C++ programming. Am I a holdover to days gone by?


    I have used one, but not in quite a while. IIRC, it was in the late '90s
    or so when I tried it. I was quite enthused for a little bit, but my
    enthusiasm slowly faded, and I think it's been a couple of years or so
    since the last time I used it at all. I've never really made any kind of
    final decision that I'll never use it again, or anything like that, but
    haven't done anything for which I'm convinced it would be at all likely
    to provide any real advantage either.

    --
    Later,
    Jerry.

    The universe is a figment of its own imagination.
    Jerry Coffin, Apr 11, 2008
    #14
  15. Lloyd Bonafide

    Arne Vajhøj Guest

    Re: Do you use a garbage collector (java vs c++ difference in "new")

    Razii wrote:
    > On Thu, 10 Apr 2008 21:43:45 -0400, Arne Vajhøj <>
    > wrote:
    >> I can not imagine any C++ runtime that makes an operating system
    >> call for each new.
    >>
    >> The runtime allocates huge chunks from the OS and then manage
    >> it internally.

    >
    > Testing the keyword "new"
    >
    > Time: 2125 ms (C++)
    > Time: 328 ms (java)
    >
    > Explain that. What I am doing different in java than in c++? Code
    > below..


    If you can prove that the only way to write inefficient code is to make
    OS calls, then you have made your point.

    But as everyone knows it is not, so your argument is completely bogus.

    Arne
    Arne Vajhøj, Apr 11, 2008
    #15
  16. Lloyd Bonafide

    Ian Collins Guest

    Re: Do you use a garbage collector (java vs c++ difference in "new")

    Razii wrote:
    > On Thu, 10 Apr 2008 19:14:12 -0500, Razii
    > <> wrote:
    >
    >>> However, part of my C++ programming style just naturally also avoids
    >>> doing tons of news and deletes in tight loops (which is, again, very
    >>> different from eg. Java programming where you basically have no choice)

    >
    > Let's test this about the keyword "new" and tight loops. Because in
    > most cases Java allocates new memory blocks on it's internal heap and
    > bypasses memory allocation mechanisms of the underlying OS, the
    > keyword "new" doesn't mean the same thing that it does in C++, where
    > each "new" allocation request is sent to the operating system, which
    > is very slow.
    >
    > Creating 10000000 new objects with the keyword 'new' in tight loop.
    >

    If a C++ programmer had to do this in the most efficient way possible,
    he/she would use a custom allocator.

    > int main(int argc, char *argv[]) {
    >
    > clock_t start=clock();
    > for (int i=0; i<=10000000; i++) {
    > Test *test = new Test(i);
    > if (i % 5000000 == 0)
    > cout << test;
    > }


    Leaks 10000000 objects.

    >
    > for (int i=0; i<=10000000; i++) {
    > Test test = new Test(i);
    > if (i % 5000000 == 0)
    > System.out.println (test);
    > }


    Does the Java allocator/GC combination recycle the objects in the loop?

    --
    Ian Collins.
    Ian Collins, Apr 11, 2008
    #16
  17. Lloyd Bonafide

    Roedy Green Guest

    Re: Do you use a garbage collector (java vs c++ difference in "new")

    On Thu, 10 Apr 2008 20:31:49 -0500, Razii
    <> wrote, quoted or indirectly quoted
    someone who said :

    >Creating 10000000 new objects with the keyword 'new' in tight loop.


    All Java has to do is add N (the size of the object) to a counter and
    zero out the object. In C++ it also has to look for a hole the right
    size and record it is some sort of collection. C++ typically does not
    move objects once allocated. Java does.

    In my C++ days, we used NuMega to find leaks, objects that were
    allocated butw never deleted even after there were no references to
    them. We never got anywhere near nailing them all. With Java this is
    automatic. You can't make that sort of screw up, though you can
    packrat. See http://mindprod.com/jgloss/packratting.html
    --

    Roedy Green Canadian Mind Products
    The Java Glossary
    http://mindprod.com
    Roedy Green, Apr 11, 2008
    #17
  18. Re: Do you use a garbage collector (java vs c++ difference in "new")

    "Razii" <> wrote in message
    news:...
    > On Fri, 11 Apr 2008 02:04:18 GMT, "Mike Schilling"
    > <> wrote:
    >
    >> In fact, given how highly
    >>optimized Java allocators are these days, the fact that C++ is
    >>taking less
    >>than 7 times as long proves that it's *not* making an OS call.

    >
    > with java -server it's 12 times slower...
    >
    > Time: 2125 ms (g++)
    > Time: 172 ms (java - server)


    Which doesn't change the conclusion.
    Mike Schilling, Apr 11, 2008
    #18
  19. Re: Do you use a garbage collector (java vs c++ difference in "new")

    "Razii" <> wrote in message
    news:...
    > On Thu, 10 Apr 2008 22:24:34 -0400, Arne Vajhøj <>
    > wrote:
    >
    >>But as everyone knows it is not, so your argument is completely
    >>bogus.

    >
    > What argument is bogus? My point was that the keyword 'new' is much
    > faster in java because JVM allocates new memory blocks on it's
    > internal heap and bypasses memory allocation mechanisms of the
    > underlying OS.


    And you're wrong, as has been demonstrated repeatedly. There's no
    point trying to explain this any further.
    Mike Schilling, Apr 11, 2008
    #19
  20. Lloyd Bonafide

    Ian Collins Guest

    Re: Do you use a garbage collector (java vs c++ difference in "new")

    Razii wrote:
    > On Thu, 10 Apr 2008 21:29:44 -0500, Sam <> wrote:
    >
    >> See how well /that/ benchmarks against Java :)

    >
    >
    > That is not the topic. The topic is how the keyword "new" behaves.
    >

    The change was fair, it compares idiomatic language use.

    Anyhow, a if you are looking at the keyword new, as simple change to the
    Test class,

    class Test
    {
    static const unsigned nItems(10000001);

    public:
    Test (int c = 0) : count(c) {}
    int count;
    void*

    operator new( size_t n ) throw( std::bad_alloc )
    {
    static Test* items = static_cast<Test*>(malloc(sizeof *items * nItems));
    static unsigned next(0);

    if( next >= nItems ) throw std::bad_alloc();

    return &items[next++];
    }

    void operator delete( void* v ) throw() {}
    };

    runs in 90mS on my box (compared to ~940mS with default new).

    As other's have said, something that's idiomatic Java isn't necessarily
    idiomatic C++. Sam pointed you to the idiomatic C++ code, my example
    shows what a C++ programmer can do when forced to use an unnatural idiom.

    --
    Ian Collins.
    Ian Collins, Apr 11, 2008
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Arne Vajhøj
    Replies:
    12
    Views:
    789
  2. Ian Collins
    Replies:
    0
    Views:
    564
    Ian Collins
    Apr 11, 2008
  3. Roedy Green
    Replies:
    14
    Views:
    1,176
    Mirek Fidler
    Apr 14, 2008
  4. asterisc
    Replies:
    6
    Views:
    491
    Mark Space
    Apr 12, 2008
  5. Ian Collins
    Replies:
    2
    Views:
    534
    Matthias Buelow
    Apr 11, 2008
Loading...

Share This Page