Slashdot Mirror


Experiences w/ Garbage Collection and C/C++?

dberger queries: "Java has helped garbage collection enter the mainstream programmer's life - but it's certainly not new or unique to java. There have been (and are) several ways to add garbage collection to C/C++ - the most active seeming to be Hans Boehm's free libgc. I'm curious if any of the Slashdot crowd has used this (or any other) C++ garbage collector in non-trivial commercial applications. If so - what were your experiences? If not, why not? (Before you ask, yes - I know that GC isn't the only difference between C++ and Java, but 'automagic memory management' is certainly part of Java's marketing luster)"

24 of 112 comments (clear)

  1. Use More Manageable Types by aster_ken · · Score: 3, Informative

    Bjarne Stroustrup, the creator of C++, has this to say on garbage collection:

    Clearly, if your code has new operations, delete operations, and pointer arithmetic all over the place, you are going to mess up somewhere and get leaks, stray pointers, etc. This is true independently of how conscientious you are with your allocations: eventually the complexity of the code will overcome the time and effort you can afford. It follows that successful techniques rely on hiding allocation and deallocation inside more manageable types.

    He goes on to give detailed examples and recommendations on how to avoid using garbage collection.

    1. Re:Use More Manageable Types by Javagator · · Score: 5, Interesting

      I was part of a project to write an image display system of about 100k lines of C++ code. Our coding standards required that we allocate resources in constructors, release them in destructors, and put objects on the stack when possible. When putting objects on the stack was not possible, we used smart pointers.

      Towards the end of the project, we finally got our company to spring for Purify. We ran Purify on the code and found a few places where we forgot to release a graphics context, and one place where we didn't follow our coding standards, but no other memory leaks. We than ran purify on a comparable C system and found hundreds of memory leaks.

      Proper use of constructors and destructors can make resource management virtually automatic.

    2. Re:Use More Manageable Types by WatertonMan · · Score: 2, Interesting
      Depending upon how you are using Java, you end up having to do a lot of things that end up being managed garbage collection anyway. i.e. not that different from C/C++ except that when you screw up you don't end up with a memory leak.

      If you use a tool like boundschecker and run it a couple of times a day, you'll avoid most of these sorts of problems in C++. It's an amazing tool I couldn't live without. One advantage to having these sorts of things flag as a "memory leak" is that you can often find subtle bugs that way.

      Admittedly because of the issue of pointers vis a vis Java, that's less of an issue in Java. But I'm not sure merely adding garbage collection is ideal in most cases.

      If you are writing high enough code that you really want garbage collection, the advantages of writing in C++ over Java are probably slight. (The speed advantage isn't that big a deal anymore and many programs don't really need that slight speed advantage anyway) If you are writing code that benefits from the fine control C++ offers you'd probably not want to trust garbage control so the point is moot.

      I'm not saying there aren't cases where garbage control is useful. However I halfway wonder if these situations wouldn't be better handles by a combination of languages. i.e. Java and C or Python and C. Code your important functions in C or C++ and put the main interface/io functions in the higher level language.

  2. Certainly.. by QuantumG · · Score: 4, Interesting
    Have a look at our project Boomerang. We're over 230k lines of code and we garbage collect everything. It's as easy as linking to Hans Boehm's libgc and adding the following lines to one of your files (probably best is the one which contains "main").

    void* operator new(size_t n) {
    return GC_malloc(n);
    }

    void operator delete(void* p) {
    }

    You can also mix collected memory with uncollected memory, but we really don't see the point. This way we can still have descructors which do useful things but the actual memory clean up is left to the garbage collector. Of course, as we write more and more new code we leave our deletes and our destructors out, and eventually we'll go through and remove them all. Until then, we can disable the garbage collector just by #if 0ing these lines out.

    --
    How we know is more important than what we know.
    1. Re:Certainly.. by AJWM · · Score: 2, Interesting

      leave our deletes and our destructors out,

      If you have destructors, do they ever get called? Destructors aren't just for freeing memory, they're also used for freeing other system resources (depending on the object). File descriptors, database connections, that kind of stuff. (Granted, you can have explicit methods to take care of that cleanup, but then you can have explicit methods to free memory too. Seems to me you want all that as automatic as possible.)

      --
      -- Alastair
  3. GC in OpenCM by Jonathan+S.+Shapiro · · Score: 5, Informative
    We made a decision early to use GC and exceptions in OpenCM, even though the application is written in C. Conceptually, it was a big success, but there were a number of hurdles along the way. Here are some things we learned:
    1. The Boehm-Weiser (BW) collector is not as portable as we had hoped. There are a number of platforms we wanted to run on where it just doesn't run at all. Relatively small changes to the target runtime can create a need to port it all over again. OpenBSD, in particular, was an ongoing hassle until we abandoned BW. Hans, I hasten to add, was quite encouraging, but he simply doesn't have time to adequately support the collector.

    2. The BW collector doesn't work in our application. OpenCM has a few very large objects. For reasons we don't really understand, this tends to cause a great deal of garbage retention when running the BW collector. Enough so that the OpenCM server crashed a lot when using it. Please note that this was NOT a bug involving falsely retained pointers, as later experience showed.

    3. Conservative collectors are actually too conservative. If you are willing to make very modest changes in your source code as you design the app, there prove to be very natural places in the code for collection, and the resulting collector is quite efficient.

    4. Independent of the collector, we also hacked together an exceptions package. This was also the right thing to do, but it's easy to trip over it in certain ways. The point of mentioning this is that once you do exceptions the pointer tracking becomes damned near hopeless and you essentially have to go to GC.

      I think the way to say this is: exceptions + GC reduces your error handling code by a lot. Instead of three lines of error check on every procedure call, the error checking is confined to logical recovery points in the program, and you don't have to mess around simulating multiple return values in order to return a result code in parallel with the actually intended return value.

    5. To provide malloc pluggability, we implemented an explicit free operation. This lets us interoperate compatibly with other libraries and do leak detection. Turns out to be very handy in lots of ways.

    6. Hybrid storage management works very well. For example, our diff routine explicitly frees some of its local storage (example) [Sorry -- this link will go stale within the next few weeks because the OpenCM web interface will change in a way that makes it obsolete. If the link doesn't work for you, try looking for the same file in .../DEV/opencm/...] This is actually quite wonderful, as it lets us build certain libraries to be GC compatible without being GC dependent. One of the challenges in using a GC'd runtime in a library is compatibility with an enclosing application that doesn't use GC. We haven't tried it yet, but it looks like our gcmalloc code will handle this.

    Eventually, we gave up on the BW collector and wrote our own. Our collector is conceptually very similar to the collector that Keith Packard built for Nickle, though we've since built from there. A variant of the Nickle collector is also used as a debugging leak tracer for X11.

    The OpenCM GC system is reasonably well standalone. We need to document it, but others might want to look at it when we cut our next release.

    On the whole, I'ld say that GC for this app was definitely the right thing to do. Once you get into object caches it becomes very hard to locate all of the objects and decide when to free them. We were able to use a conservative approach with no real hassle, and heap size is fairly well bounded by the assisted GC approach we took.

    On the other hand, I would not recommend a pure conservative collector for a pro

    --
    Jonathan S. Shapiro (The EROS Guy)
  4. There's another way. by Lally+Singh · · Score: 4, Informative

    Garbage collection has costs:
    - The obvious: CPU & memory overhead for the checking and tracking. I can't comment on the amount here, but it is a generalized solution, so you forego the optimization opportunities that you'd otherwise have.
    - The subtle: Memory allocation can become a major bottleneck in multithreaded systems. Garbage collection has similar issues.
    - The irritating: you don't know when your destructors are called.

    Another way: Smart Pointers. They're simple wrappers around the types that act like pointers, but they can make sure your objects live as long as you need and no longer. The big trick is knowing which kind of smart pointer you want.
    - Reference Counting Smart Pointer (RCSP for short): this type of smart pointer will keep of how many RCSPs are pointing to the same object. It'll delete the object when the last RCSP is destroyed. A good one is the boost shared_ptr. Available for free from www.boost.org. This type is great for general use.

    - Owning Smart Pointer (OSP): this type is specialized for those cases when the refcnt is never more than 1. When you assign one OSP (a) to another (b), the new OSP (a) gets ownership of the referred object, and the old one (b) is automatically set to null. When an OSP that isn't set to null is destroyed, it deletes the object it owns. It's great for parameter passing, return values, and objects you want dead at the end of the current scope, even if there's an exception. The STL comes with auto_ptr, which works this way.

    You can use an RCSP wherever you can use an OSP, but not the other way around. The STL containers are a great example.

    Sure it's not as easy as 'allocate and forget,' but you won't have the (sometimes very costly) expense of full-blown garbage collection.

    Also, you can optimize your smart pointers for individual types (through template specialization). A great example is to give the no-longer-needed object back to a pool for later reuse.

    This is really a quick, quick overview. For the meat & potatoes, go read Effective STL by Scott Meyers.

    I've tried really hard to be fair & polite. There's probably still a bias, but I'm really trying!!

    --
    Care about electronic freedom? Consider donating to the EFF!
    1. Re:There's another way. by swillden · · Score: 5, Insightful

      You repeat some common myths about GC; allow me to counter them.

      The obvious: CPU & memory overhead for the checking and tracking. I can't comment on the amount here, but it is a generalized solution, so you forego the optimization opportunities that you'd otherwise have.

      Malloc/free and new/delete (without pooling) are also generalized solutions, and they also consume CPU and memory overhead for checking and tracking. There is good reason to believe that in the right type of language (which C and C++ are not) that GC can actually be much more efficient than manual deallocation, mainly because it can do its work in larger batches, and because it can reorganize objects in memory to make allocating more efficient. Contrast a simple single-heap malloc implementation, which has to scan a free list looking for a sufficiently large block against a copying garbage-collected system where the allocation pool is simply a large contiguous block from which you just grab the first 'n' bytes.

      If you look on Boehm's web site, you can find a few papers comparing the performance of conservative GC for C with optimized malloc/free implementations. malloc/free wins, but not by as much as you'd expect.

      The subtle: Memory allocation can become a major bottleneck in multithreaded systems. Garbage collection has similar issues.

      Actually, GC *eases* the issues associated with recovering memory in multithreaded systems. Why? In a multi-threaded program with manual deallocation, both allocation and deallocation occur in every thread context. In a GC system, all deallocation is typically concentrated in a single thread, the GC thread. Allocation is still spread across threads but the required interlocking is hugely reduced since the GC thread can do all of the reclaiming, block coalescing and free list construction (if that's the technique used) without any interference from the other threads. It will have to acquire a mutex to place the recovered blocks back where the active threads can get them, of course.

      Generational, copying GCs can do even better, but not for C or C++.

      The irritating: you don't know when your destructors are called.

      As experience with finalize methods in Java has shown, you should really treat GC as a way of having infinite memory. The problem with finalizers/destructors is that not only do you not know when they'll be called, you have no way of knowing that they'll *ever* be called. That means that they're effectively useless and add significant complexity and overhead for little or no return.

      IMO, if you want to use C++ with GC, you should make sure that objects that have non-trivial destructors (those that do something besides memory management) get destructed normally, and just let GC handle the memory.

      Reference Counting Smart Pointer (RCSP for short)

      They're useful, but I'd hardly call them great. Reference counting is *far* more compute-intensive than scanning-type garbage collection. And then there's the problem of circular references, which will never be reclaimed. Of course, it's not that hard to avoid those situations most of the time, but with GC you don't have to care.

      Owning Smart Pointer (OSP) ... auto_ptr

      These are very useful, and conscientious use of them will eliminate 95% of memory leaks and dangling pointers. OTOH, they don't work when things get complex enough that ownership isn't simple and clear.

      Also, you can optimize your smart pointers for individual types (through template specialization). A great example is to give the no-longer-needed object back to a pool for later reuse.

      Generally, I would do this through specialized new/delete, rather than specialized smart pointers. Regardless of the mechanism, though, pooled allocation is the absolute best thing you can do to minimize the cost of memory management in your application. The reason is, of course, that you build the pooling based on your knowledge of the actual usage characteristics of the objects; knowledge that no general-purpose memory manager can possibly have.

      --
      Note to ACs: I usually delete AC replies without reading them. If you want to talk to me, log in.
    2. Re:There's another way. by jdfekete · · Score: 2, Insightful

      I used BW Garbage Collection on an Information Visualization system here available under the GPL.
      It works, but with some problems, mainly due to the fact that it doesn't knows enough of the OS, in particular large pages allocated by libraries that it has to scan for pointers. There is nothing that cannot be fixed in theory, but systems are not designed for it right now.
      On my visualization application, it spends seconds scanning some memory mapped zone opened by NVidia OpenGL implementation (this is a guess from looking at the stack trace in gdb).

      For the performance talk, there are interesting figures in the book Garbage Collection
      and at Boem's site showing that reference counting costs more than garbage collection.
      However, reference counting is predictable and does not interrupt interactive applications at random moments.
      In particular for multithreaded applications, reference counts should be guarded by a mutex that is very expensive and can be avoided using a GC.

      One possible alternative to C++ with BW is using gcj, the Gnu Java Compiler. It uses the same back-end than G++ for producing optimized code but is closely tied to the BW garbage collection, providing information about how objects are organized in memory, improving the marking-time of the GC.
      gcj produces code that can be linked with C and C++ without having to resort to JNI.

  5. C++ very expressive indeed by Latent+Heat · · Score: 2, Troll
    C++ is very expressive indeed, and the example shows that C++ is good at something for which many would consider a scripting language to be required. But like some scripting languages, this C++ code fragment descends into a mix of Egyption hieroglyphics and Hittite cuneiform rather quickly.

    So please tell me what

    typedef vector::const_iterator Iter;

    (or rather vector::const_iterator) is supposed to mean. I suppose vector is a templated class, but how does ::const_iterator come up with a type name -- I thought :: either references a static field or a class member function?

    And what is the deal with the sort(,) as a free-standing function? Following OO principles, shouldn't the vector object v know how to sort itself with a call to v.sort()? And what the heck is this const_iterator type anyway that you can do ++ and * on it -- looks an awful lot like a pointer -- oops, I forgot, you can overload ++ and * to make "safe" operations on what are really objects look like "dangerous" pointer operations which the C/C++ community is in custom of using.

    In principle, all the stuff done in Java and perhaps in scripting languages could all be done elegantly and expressively in C++ if us mere mortals ever figure out how to use the darned thing. But there is a kind of uniformity to Java (all object variables being GC'd heap references, collection and iterator types working with generic Object's that we cast to what the object is and rely on runtime type checking, don't worry-be happy allocation of these objects where we grab towels from the rack and leave them on the bathroom floor for the hotel maid to pick up) that simply feels more comfortable.

    C++ is the music of Bach: elegant, mathematical, intricate, and expressive, but most musicians performing in front of audiences don't understand it and it is played as a dull jumble and mishmash and audiences gaze at Bach stuck at the beginning of a recital as a chore to get through. Java is the music of Mozart: simplified, standardized, predictable, and economical, but musicians of this era understand it and play it with gusto, and audiences love it because it sound so happy and makes them feel uplifted.

    1. Re:C++ very expressive indeed by ville · · Score: 3, Informative

      And what is the deal with the sort(,) as a free-standing function? Following OO principles, shouldn't the vector object v know how to sort itself with a call to v.sort()?


      Not necessarily. If you have multiple types of containers and you can write a single sort that can sort all those types then why implement it in all of them instead of just once.


      Here is an article that deals with the question which functions should be members and which shouldn't. It uses the std::string as an example which has a lot of methods that turns out shouldn't have to be.



      // ville

    2. Re:C++ very expressive indeed by cookd · · Score: 3, Insightful

      Classes can have inner classes as well as typedefs. Those are in the namespace of the class, so the namespace operator :: is used to access them.

      And the sort question was answered by somebody else, but here is a bit more on the subject: if a bunch of classes share portions of their interfaces, and the shared subset is enough to perform a useful operation, why not share the implementation of the operation? While you could certainly "tell a vector to sort itself", it makes just as much sense to "apply the sort operation to a vector". Sort is not a primitive operation on a vector, it doesn't require access to the internals of the vector for efficient implementation, so there is no reason to make it a member.

      The rest I agree with. A C++ master can do wonderous things, but there are few C++ masters out there. Very simply put, it is really tough to come up with the BEST way to do something in C++ -- there is always more than one way to do it, and doing it perfectly can take an impossible amount of time.

      Also, since many useful concepts are possible to implement optimally, yet not built-in to the language, there are way too many libraries. How many different ways are strings expressed? Too many.

      --
      Time flies like an arrow. Fruit flies like a banana.
    3. Re:C++ very expressive indeed by lovelace · · Score: 3, Interesting
      So please tell me what

      typedef vector::const_iterator Iter;

      (or rather vector::const_iterator) is supposed to mean. I suppose vector is a templated class, but how does ::const_iterator come up with a type name -- I thought :: either references a static field or a class member function?
      No, classes can have types too. In this case, a vector::const_iterator is an iterator over the vector type that can point to anything in the container (the vector) but cannot change anything in it. A read-only pointer, if you will.
      And what is the deal with the sort(,) as a free-standing function? Following OO principles, shouldn't the vector object v know how to sort itself with a call to v.sort()? And what the heck is this const_iterator type anyway that you can do ++ and * on it -- looks an awful lot like a pointer -- oops, I forgot, you can overload ++ and * to make "safe" operations on what are really objects look like "dangerous" pointer operations which the C/C++ community is in custom of using.
      C++ is not just an OO language. It's a multi-paradigm language. In addition to OO, you can also do procedural , functional or generic programming. The key is to use the right tool for the right job, not to force everything into the OO model.

      As far as iterators looking like pointers, there's a reason for that. They're modeled after pointers! This way a regular pointer can be used with any generic algorithm (like sort).

      C++ is not just Bach. It's the entire classical genre. Java, while nice for some things, just falls short at most things. All things do not fit into the object oriented model and trying to put them there when they don't belong is a recipe for disaster. While I disagree with your characterization of Java as Mozart, I will say this. I learned Mozart when I was a beginning music student. After too long, though, it became predictible and downright boring. There was so much more I wanted to do with music. So, I branched out to Beethoven or Strauss. From there I went to even more exotic things like Bartok or Shostikovich. I felt much more fulfilled as a musician and could express things I never could while just playing Mozart. C++ is like this. It's not just OO or procedural or functional or generic. It can be whatever you want it to be and after using it for a while, other languages just don't match up.

  6. A bit off-topic, perhaps. by bo0ork · · Score: 3, Informative
    I've wrote an OO language back in 1993 that's being used by two medium-sized companies. It's garbage collected, and it's kernel is written in C. The language is not interpreted; it gets translated into C and then compiled. The applications written with the language are fairly large. The source code of one is 28MB uncompressed. I'll skip the general implementation details, and just go over the garbage collection approach I used. These definitions are true for that language; they're not meant to be general.

    A program variable is either a global variable, a stack variable, a class variable or an instance variable. Global and stack variables are held in lists. Class and instance variables are kept inside objects.

    Every class object has a global variable that always refers to it.

    Any object that is not, and that can not become referenced (directly or indirectly) by a global or stack program variable is garbage.

    Each object has a 'not-garbage' flag.

    For each global and stack variable, if the referenced object is not marked not-garbage, mark the referenced object as not-garbage, and recurse for that objects contained variables.

    Delete all objects that are not marked not-garbage.

    There are a few more twists, like handling return values on the stack, but this algorithm correctly handles self-referencing objects no matter the complexity.

    --
    Does everything include nothing?
  7. GC costs by greppling · · Score: 5, Informative
    One thing you didn't mention is that GC is deemed to have pretty high processor cache-miss costs. The obvious part is that the GC run itself is basically pointer chasing, i.e. pretty much the worst thing you can do cache-wise. And after the GC run, the cache is clobbered with stuff useless for continuing the work.

    There is another indirect cost pointed out by Linus Torvalds in a lengthy post to the gcc mailining list. The executive summary is that (he thinks that) memory that is not to be used anymore should be freed immediately. Otherwise, the data in there will keep lying around in the data cache. Also, he claims that explicit ref-counting gives you advantages for optimization: Assume you have to make some modifications to a data structure, but you don't want other parts of the program to see the modifications. Without ref-counting, you have to copy all the data structure before modifying it. With ref-couting, you can omit the copying if you are the only one with access to the data structure.

    And finally, he thinks that GC makes it too easy to write pointer-chasing-heavy code---as that kind of code is bad for cache behaviour all the time.

    It is an ongoing discussion whether GC really has that bad effects on performance of GCC. But Linus Torvalds seems to have very good points. (And some of them certainly cannot be taken into account in a "GC cost is less than hand-written memory management"-paper.)

    1. Re:GC costs by Hard_Code · · Score: 3, Interesting

      Can anybody informed tell me whether we have not ALREADY lost the war against pointer-chasing and cache clobbering? Any OOP or interpreted language (the vast majority of mainstream code) is doing this already, true?

      --

      It's 10 PM. Do you know if you're un-American?
    2. Re:GC costs by be-fan · · Score: 2, Insightful

      Your description is slightly inaccurate. He said that explicitly freeing allows the next alloc to reuse a given chunk of cache-hot memory, while the GC will ignore that memory and allocate a cache-cold chunk instead.

      --
      A deep unwavering belief is a sure sign you're missing something...
  8. It's okay by Anonymous Coward · · Score: 4, Interesting

    I've used a garbage collection system in a C project before and it works surprisingly well. The problem with GC in C though is that it is possible and legal to,

    o allocate memory
    o write the pointer to a disk
    o lose the pointer in memory
    o read the pointer back off the disk,
    o make use of the pointer

    With all GC strategies I'm aware of, by the time you read the pointer from the disk the memory may well have been freed.

    I'm not saying that this style of programming is a generally good idea but it is used in certain, specialised situations and therefore not suitable for a garbage collecting language.

  9. Boehm collector on large application by Inode+Jones · · Score: 2, Informative
    I am using the BDW collector in an EDA tool. EDA tools store large databases of circuit connectivity, and for various reasons we don't want to be bothered with explicit memory management.

    The salient points:

    Destructors are not Called

    If an object is allocated in collectible memory, then its destructor will not be called when the object is collected. Therefore, destructors are pretty much useless and your code must be designed to work without them.

    Actually, if your object derives from class gc_cleanup, then its destructor will be called. However, due to the handling of cleanup functions in the BDW collector, cycles of such objects will never be collected. For this reason, I don't use gc_cleanup much.

    Allocating Collectible Memory

    By default, C++ allocates objects in the "malloc" heap. The BDW collector maintains a separate heap. In effect, there are four types of memory:

    • scannable and collectible (GC)
    • scannable, but uncollectible (NoGC)
    • non-scannable, but collectible (GC_atomic)
    • non-scannable, non-collectible (malloc)

    "Scannable" refers to the property that objects in the heap are scanned for pointers. "Collectible" refers to the property that objects in the heap will be deallocated if no further references are found.

    These four memory types are an issue when you interact with STL and third-party class libraries. By default, STL uses the malloc heap. If you want, say, a std::vector in collectible memory, then you need to write an allocator to get it. The most recent versions of the collector come with such a beast; the version I started using did not.

    Similarly, std::string is reference-counted, and in the malloc heap. Here, rather than using an allocator to force it into the collectible heap, I wrote my own lightweight GCString class, which stores the string as an immutable object, and relies on the collector for cleanup.

    Third-party class libraries such as ANTLR may use reference-counted objects; you need to bridge between GC and non-GC applications carefully.

  10. The wonders of moderation by Latent+Heat · · Score: 2, Interesting
    The original discussion was whether anyone used/benefited from a C++ implementation of GC. A poster responded with a link to Stroustrup pointing out that C++ is so expressive that you don't need GC -- you can embed the memory management in stack-frame objects which take care of it for you.

    I pointed out that Stroustrup's example shows the expressive power of C++, but there is a big "huh?" factor of reading the code on account that many of us mere mortals are not rehearsed in the use of templates and STL, and there was something to be said for Java and GC, not just for safety but for simplicity of expression and code reading by maintenance programmers.

    Yours is one of three comments to my remarks, answering questions I had raised, disagreeing with some points, agreeing with others, but otherwise engaging in a reasoned discussion of the merits of C++ and its advanced features (templates and STL). But I get moderated down and flagged "troll" -- oh well.

  11. Re:Don't Free Memory Unless You Have To by haystd · · Score: 2, Informative

    With the first example I belive the point is that the string and vector classes will clean up themselves when they go out of scope (when their destructors are called). STL is very helpful especially when supplemented with the Boost libraries.

  12. Very happy... by DrCode · · Score: 2, Insightful

    A few years ago, I used the Boehme GC when writing a pair of compilers (Verilog/VHDL) in C++. I was very happy with the result, since it was rare for GC even to get called at all. It was also surprising how much simpler code gets when you don't have to worry about deleting objects.

  13. Good Book on Garbage Collection by umofomia · · Score: 2, Insightful

    There's a really good book about everything you ever needed to know about garbage collection. Although most of the book deals with garbage collection techniques in general, it has two complete chapters devoted to implementing and using garbage collectors in C and C++ and which ones you should use depending on your application needs.

  14. Re:the key to it all by swillden · · Score: 2, Insightful

    iow, it's really worthwhile to think about memory management issues, who owns memory, etc, and not just for the free() call, but for the design itself. It pays back a lot to think of these things, and use GC for particular cases that can benefit.

    I agree with this, actually. I've seen many cases where having to think about object lifetimes has given me clearer insights into the problem domain and into the design, and resulted in better, tighter, cleaner and more maintainable code than would have been the case otherwise.

    However, I've also seen some systems where the cleanest, most flexible and most maintainable design made keeping track of object lifetimes a real bitch. So while I wholeheartedly agree that being forced to think about memory management can improve the overall quality of most designs, there are circumstances where having to manage memory manually forces you to choose an inferior application architecture. In those cases, GC is a *huge* win, since choosing the right structure is the single most important thing you can do to facilitate both implementation and maintenance.

    In addition, there are those cases where the code just doesn't matter that much; and GC is certainly an aid to getting the job done quickly, because it removes a large class of concerns from the programmer.

    I'm not necessarily a huge fan of GC, sometimes it's great, sometimes it sucks -- it's just another tool. But I had to respond in this thread because there are a lot of misconceptions about GC (and the alternatives, like refcounting smart pointers).

    --
    Note to ACs: I usually delete AC replies without reading them. If you want to talk to me, log in.