11

As far as I know, in case of an uncaught exception, C++ destroys the local variables immediately, Java releases the references and leaves the rest for the garbage collector.

Is this right? What exactly is the difference between Java and C++ on this issue? in other words, which of these two languages is considered better in terms of stack unwinding issue? :)

Feyyaz
  • 3,147
  • 4
  • 35
  • 50
  • 3
    Subjective - define "better". – razlebe Mar 31 '10 at 08:39
  • Java implements a proper garbage collector, so in theory, you should never have to worry about an object not destroying everything it creates on stack. C++ assume you are being careful. – thecoshman Mar 31 '10 at 08:53
  • 4
    Java implements a _memory_ garbage collector. Temporary files are not garbage collected, and may be leaked by a stack unwind as a result. On the other hand, in C++ stack unwinding calls destructors, which in addition to the memory cleanup can also clean up temporary files and other resources. So Java is easier and C++ more flexible, a standard engineering tradeoff. – MSalters Mar 31 '10 at 10:26
  • @MSalters: +1 because it clarifies a fundamental difference between C++ and Java on resources handling. – paercebal Apr 14 '10 at 16:22

4 Answers4

10

I'm going to get flamed for this but...

C++ is hands down better than Java on the stack unwinding front--there's just no contest. C++ object destructors fire all the way back up the stack until the catch point is reached--releasing all managed resources gracefully along the way.

As you said, Java leaves all of this at the mercy of the non-deterministic garbage collector (worst case) or in the hands of whatever explicitly crafted finally blocks you've littered your code with (since Java doesn't support true RAII). That is, all the resource management code is in the hands of the clients of each class, rather than in the hands of the class designer where it should be.

That said, in C++, the stack unwinding mechanism only functions properly if you're careful to ensure that destructors themselves do not emit exceptions. Once you've got two active exceptions, your program abort()'s without passing go (and of course without firing any of the remaining destructors).

Drew Hall
  • 28,429
  • 12
  • 61
  • 81
  • In C++ the objects created on the stack are get the destructor called, but that not happens for the objects on the heap, referenced by a pointer with in a local variable. – Mnementh Mar 31 '10 at 09:09
  • 1
    @Mnementh: except for heap objects that are properly owned by an object with a destructor. – quamrana Mar 31 '10 at 09:28
  • @quamrana: Yes, as I explained in my answer. – Mnementh Mar 31 '10 at 09:32
  • This behaviour has absolutely nothing to do with stack unwinding, and everything with the possibility of allocating objects on the stack in the first place. I'll take non-deterministic garbage collection over manual memory management every day. Java beats C++ on memory management hands down - there's just no contest. – Michael Borgwardt Mar 31 '10 at 09:36
  • @Michael: Stack objects & stack unwinding are part & parcel to C++'s much more robust resource management strategy. It's certainly true that Java's stack unwinding model is broken because Java doesn't have stack objects, but I think you're splitting hairs. And I strongly disagree with you on the Java/C++ memory management front--I much prefer the consistency of all forms of resource management in C++ to Java's "memory is special" model that seems to make management of any other resource horribly painful. Memory management in C++ is not hard to get right, contrary to popular belief. – Drew Hall Mar 31 '10 at 09:49
  • Java stack unwinding is broken, as explained it works like in C++. But Java has no explicit object creation on the stack. You're right that management of resources besides memory is somewhat harder in Java, but for the case of an exception the OP is talking about, you have to take care in C++, to avoid memory leaks for heap-objects. That's also hard. So as always: For some cases C++ works better, for other Java. No flaming from either side is needed. – Mnementh Mar 31 '10 at 11:10
  • 3
    @Mnementh: In C++ you just have to have discipline: heap allocations are held by smart pointers, period. End of memory management problems. Sorry, I didn't mean to rant about Java but sometimes I feel like they created "a better C++" by removing all the good parts of C++. – Drew Hall Mar 31 '10 at 11:28
  • @Michael Borgwardt: Unless you're, like me, writing a commercial Java application... I start to regret Java a lot: non-deterministic GC is a major pain when you're shipping to hundreds and soon thousands of users. Good luck explaining to them why suddenly their app seems stuck: oh but this is normal you know, this *rocks*, this is Java's non-deterministic GC! This is much better than C++! Look, as a programmer, I don't care about freeing objects! As a user you do of course. Btw if there's one thing that I hate about IntelliJ it's when it's doing a full GC... Maybe Java ain't perfect? – SyntaxT3rr0r Mar 31 '10 at 11:39
  • 1
    @WizardOfOdds: your users care about freeing objects? Nonsense. They care about apps not crashing, which is decidedly easier to do in Java, and about performance, which may be a bit harder, but is certainly not impossible. Problem with GC pauses usually can be addressed by tuning the GC options of the JVM. – Michael Borgwardt Mar 31 '10 at 12:13
  • 2
    @Drew Hall: Self-limiting to smart-pointers? Why do you cut out the good parts of C++? ;-) – Mnementh Mar 31 '10 at 12:22
  • 1
    About this RAII thing, if we have a problem with resources (say, a db connection) in Java, why doesn't it have a destructor like mechanism that is called when the garbage collector collects the object. That way, we would guarantee that the resource would be closed, no matter when. Right? – Feyyaz Mar 31 '10 at 15:11
  • @Michael Borgwardt: You are contradicting yourself: On one hand, you tell Drew Hall **Java beats C++ on memory management hands down**, and when contradicted, tell WizardOfOdds **your users care about freeing objects?**. C++ RAII mechanism is unmatched when compared with Java's broken resource handling. At least, the C# people got it right with their `using` keyword and their **dispose** pattern. – paercebal Apr 14 '10 at 16:27
  • 1
    @paercebal where do you see a contradiction? The statement that *users* care about freeing objects is patently absurd; they don't have the fainted idea what "freeing objects" even means. And while Java's handling of non-memory resources might not be as good as RAII (in cases where RAII can be applied), this is a small price to pay for not having to deal with manual memory management. – Michael Borgwardt Apr 14 '10 at 17:34
  • @sahs: um... that mechanism exists. It's called "finalizer". The problem with it is that since it depends on the garbage collection of the related object, it can be delayed arbitrarily. – Michael Borgwardt Apr 14 '10 at 17:37
5

Stack unwinding is specifically calling destructors of all fully constructed objects up the call chain up to the point where the exception is caught.

Java simply has no stack unwinding - it doesn't do anything to objects if an exception is thrown. You have to handle the objects yourself in catch and finally blocks. This is mainly why C# introduced using statements - they simplify calling IDisposable.Dispose(), but again that's not the complete replacement for C++ stack unwinding.

sharptooth
  • 167,383
  • 100
  • 513
  • 979
  • To ask the question here may be better: why doesn't Java have a destructor like mechanism that is called when the garbage collector collects the object? That way, we would guarantee our resources to be closed; no matter when, since we are interested more in handling the memory leaks. – Feyyaz Mar 31 '10 at 16:25
2

You are quite correct, C++ destroys all local variables, in reverse order, as it exits each function on the stack - just as if you were programmatically executing return - and out of main().

quamrana
  • 37,849
  • 12
  • 53
  • 71
2

For the stack do both the same: They release the stack for the blocks that you leave with the exception. In Java all primitive types (int, double etc.) are saved directly, local variables of this type are released in this moment. All objects are saved through references in local variables, so the references are removed, but the objects itself stay on the heap. If this was the last reference to the object, they are released on the next garbage collection. If in C++ are objects created on the heap and the local variables keep a pointer, the objects on the heap aren't released automatically, they stay on the heap forever (yes, you get a MEMORY LEAK). If you have saved objects on the stack, then the destructor is called (and may release other referenced objects on the heap).

Mnementh
  • 50,487
  • 48
  • 148
  • 202
  • 2
    True, but smart pointers in C++ let you destroy heap-allocated objects automatically as well. – sharptooth Mar 31 '10 at 09:11
  • 2
    In fact they work exactly the same way. Stack unwinding calls their destructors and their destructors in turn destroy the corresponding heap-allocated objects. – sharptooth Mar 31 '10 at 09:17
  • Yes, that's the way they are implemented. I meant they work different, as you don't need that much care to avoid memory-leaks by using smart pointers. – Mnementh Mar 31 '10 at 11:11
  • What sharptooth wanted to tell, I guess, is that you should have mentionned smart pointers in your discussion, too. Something like: *The objects are still on the heap, but a stack-based smart pointer will free it as soon as possible*. – paercebal Apr 14 '10 at 16:33