Java and C++ on Stack Unwinding issue
Asked Answered
L

4

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? :)

Lynd answered 31/3, 2010 at 8:35 Comment(4)
Subjective - define "better".Centenarian
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.Fishery
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.Globeflower
@MSalters: +1 because it clarifies a fundamental difference between C++ and Java on resources handling.Hemeralopia
R
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).

Renal answered 31/3, 2010 at 8:54 Comment(14)
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.Solifidian
@Mnementh: except for heap objects that are properly owned by an object with a destructor.Clance
@quamrana: Yes, as I explained in my answer.Solifidian
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.Eleventh
@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.Renal
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.Solifidian
@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++.Renal
@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?Nuss
@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.Eleventh
@Drew Hall: Self-limiting to smart-pointers? Why do you cut out the good parts of C++? ;-)Solifidian
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?Lynd
@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.Hemeralopia
@Hemeralopia 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.Eleventh
@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.Eleventh
P
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.

Prague answered 31/3, 2010 at 8:37 Comment(1)
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.Lynd
C
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().

Clance answered 31/3, 2010 at 8:47 Comment(0)
S
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).

Solifidian answered 31/3, 2010 at 9:6 Comment(4)
True, but smart pointers in C++ let you destroy heap-allocated objects automatically as well.Prague
In fact they work exactly the same way. Stack unwinding calls their destructors and their destructors in turn destroy the corresponding heap-allocated objects.Prague
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.Solifidian
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.Hemeralopia

© 2022 - 2024 — McMap. All rights reserved.