Reputation: 27629
So if I understand well, Garbage collection automatically deallocates objects that are not used by the program anymore. like the garbage collector in java.
I hear in languages like C that don't support garbage collection the programs can have memory leaks and subsequently exhaust the memory.
So what are the errors that programmer make in languages like C that don't support garbage collection? I would guess not deallocating objects after they're not used anymore. But are these the only errors that we can make because of the lack of a garbage collector?
Upvotes: 17
Views: 10123
Reputation: 71
memory leaks in C++ are not inherent to the language, they are due to programming errors. Valgrind is a wonderful tool for finding those errors which makes it easy to fix them. Smart pointers are in built tool of the language to help auto delete stuff when it goes out of scope, but circular references can prevent the last reference from a parent to member and that member to its parent from being deleted. point is if you avoid using smart pointers for circular references (use RAW pointers or "&" refernces for those) and you run your C++ code through valgrind you won't have memory leaks. and your code will probably be about 2x faster than Java without having done anything special. This is not to advocate C++ over Java, Java has other features like reflection that are useful. besides language features the decided factor between Java an C++ is generally whether developer time or computing resources are more "expensive" under any metric you care to use. Java is the industrial strength application/architecture language. C++ is the performant compute language that can be called from just about any other language out there. The project I'm working on is largely a Java architecture with some C++ components (legacy code) and stuff that needs to be performant (I'm the C++ guy on the team writing the math intensive code that needs to be performant)
Upvotes: 0
Reputation: 23311
In C, you have to manually call free
on memory allocated with malloc
. While this doesn't sound so bad, it can get very messy when dealing with separate data structures (like linked lists) that point to the same data. You could end up accessing freed memory or double-freeing memory, both of which cause errors and can introduce security vulnerabilities.
Additionally, in C++, you need to be careful of mixing new[]/delete
and new/delete[]
.
For example, memory management is something that requires the programmer to know exactly why
const char *getstr() { return "Hello, world!" }
is just fine but
const char *getstr() {
char x[BUF_SIZE];
fgets(x, BUF_SIZE, stdin);
return x;
}
is a very bad thing.
Upvotes: 2
Reputation:
IMO, garbage collected languages have complementary problems to those in non-garbage-collected languages. For every issue, there is a non-GC-characteristic bug and a GC-characteristic bug - a non-GC programmer responsibility and a GC programmer responsibility.
GC programmers may believe that they are relieved of responsibility for freeing objects, but objects hold resources other than memory - resources that often need to be released in a timely way so that they can be acquired elsewhere - e.g. file handles, record locks, mutexes...
Where a non-GC programmer would have a dangling reference (and very often one that isn't a bug, since some flag or other state would mark it as not to be used), a GC programmer has a memory leak. Thus where the non-GC programmer is responsible for ensuring that free/delete is called appropriately, a GC programmer is responsible for ensuring that unwanted references are nulled or otherwise disposed of appropriately.
There is a claim in here that smart pointers don't deal with garbage cycles. This need not be true - there are reference counting schemes that can break cycles and which also ensure timely disposal of garbage memory, and at least one Java implementation used (and may still do) a reference counting scheme that could just as easily be implemented as a smart pointer scheme in C++.
Concurrent Cycle Collection in Reference Counted Systems
Of course this isn't normally done - partly because you may as well just use a GC language, but also partly IMO because it would break key conventions in C++. You see, lots of C++ code - including the standard library - relies heavily on the Resource Allocation Is Initialisation (RAII) convention, and that relies on reliable and timely destructor calls. In any GC that copes with cycles, you simply cannot have that. When breaking a garbage cycle, you cannot know which destructor to call first without any dependency issues - it may not even be possible, since there may be more cyclic dependencies than just memory references. The solution - in Java etc, there is no guarantee that finalizers will be called. Garbage collection only collects one very specific kind of garbage - memory. All other resources must be cleaned up manually, as they would have been in Pascal or C, and without the advantage of reliable C++-style destructors.
End result - a lot of cleanup that gets "automated" in C++ has to be done manually in Java, C# etc. Of course "automated" needs the quotes because the programmer is responsible for ensuring that delete is called appropriately for any heap-allocated objects - but then in GC languages, there are different but complementary programmer responsibilities. Either way, if the programmer fails to handle those responsibilities correctly, you get bugs.
[EDIT - there are cases where Java, C# etc obviously do reliable (if not necessarily timely) cleanup, and files are an example of this. These are objects where reference cycles cannot happen - either because (1) they don't contain references at all, (2) there's some static proof that the references it contains cannot directly or indirectly lead back to another object of the same type, or (3) the run-time logic ensures that while chains/trees/whatever may be possible cycles are not. Cases (1) and (2) are extremely common for resource-managing objects as opposed to data-structure nodes - perhaps universal. The compiler itself cannot reasonably guarantee (3), though. So while standard library developers, who write the most important resource classes, can ensure reliable cleanup for those, the general rule is still that reliable cleanup of non-memory resources cannot be guaranteed for a GC, and this could affect application-defined resources.]
Frankly, switching from non-GC to GC (or visa versa) is no magic wand. It may make the usual suspect problems go away, but that just means you need new skillsets to prevent (and debug) an whole new set of suspects.
A good programmer should get past the whos-side-are-you-on BS and learn to handle both.
Upvotes: 13
Reputation: 192
Please don't compare OO languages (Java, C#) with non OO languages (C) when talking about garbage collection. OO languages (mostly) allow you to implement GC (See comment about smart pointers). Yes they are not easy but they help a lot, and they are deterministic.
Also, how do GC-languages compare to non GC-languages when considering resources other than memory, eg. files, network connections, DB connections, etc...
I think answering that question, left to the reader, will shed some light on things too.
Upvotes: -3
Reputation: 7137
Usually, languages with Garbage Collection restrict the programmer's access to memory, and rely on a memory model where objects contain:
In comparison with a non-GC language, there are two classes of errors that are reduced/eliminated by the model and the restricted access:
Memory Model errors, such as:
Pointer errors, such as:
There are more, but those are the big ones.
Upvotes: 0
Reputation: 17960
Some non-GC languages offer constructs called reference counting smart pointers. These try to get around some problems such forgetting to deallocate memory or trying to access invalid memory by automating some of the management functions.
As some have said, you have to be "smart" about "smart pointers". Smart pointers help to avoid a whole class of problems, but introduce their own class of problems.
Many smart pointers can create memory leaks by:
These problems shouldn't be encountered in fully GC'ed environments.
Upvotes: 2
Reputation: 56113
Another common error is reading or writing memory after you've deallocate it (memory which has since been reallocated and is now being used for something else, or memory which hasn't been realoocated yet and which is therefore currently still own by the heap manager and not by your application).
Upvotes: 0
Reputation: 147164
In addition to other comments, manual memory management makes certain high performance concurrent algorithms more difficult.
Upvotes: 2
Reputation: 2157
Dellocating things you need
Not deallocating things you no longer need (because you're not tracking allocations/use/frees well)
Re-allocating new instances of things that already exist (a side-effect of not tracking properly)
De-allocating something you've already freed
De-allocating something that doesn't exist (a null pointer)
There are probably more. The point is: managing memory is tricky, and is best dealt with using some sort of tracking mechanism and allocating/freeing abstraction. As such, you might as well have that built into your language, so it can make it nice and easy for you. Manual memory management isn't the end of the world -- it's certainly doable -- but these days, unless you're writing real-time code, hardware drivers, or (maybe, possibly) the ultra-optimised core code of the latest game, then manual effort isn't worth it, except as an academic exercise.
Upvotes: 20
Reputation: 15009
In addition to what silky says you can also double deallocate something.
Upvotes: 3
Reputation: 55082
Well, the errors you can make are:
There are other errors you can make, but those are the ones that relate specifically to garbage collection.
Upvotes: 8