简体   繁体   English

Stack Unwinding问题上的Java和C ++

[英]Java and C++ on Stack Unwinding issue

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. 据我所知,在未捕获异常的情况下,C ++会立即销毁局部变量,Java会释放引用并将其余部分留给垃圾收集器。

Is this right? 这是正确的吗? What exactly is the difference between Java and C++ on this issue? Java和C ++在这个问题上究竟有什么区别? in other words, which of these two languages is considered better in terms of stack unwinding issue? 换句话说,就堆栈展开问题而言,这两种语言中的哪一种被认为更好? :) :)

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 ++比Java更好 - 没有竞争。 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. C ++对象析构函数一直触发堆栈直到达到捕获点 - 沿途释放所有托管资源。

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). 正如你所说的那样,Java将所有这些都置于非确定性垃圾收集器(最坏的情况)或者任何明确制作的最终块的手中,你已经散布了你的代码(因为Java不支持真正的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. 也就是说,在C ++中,如果您小心确保析构函数本身不会发出异常,则堆栈展开机制只能正常运行。 Once you've got two active exceptions, your program abort() 's without passing go (and of course without firing any of the remaining destructors). 一旦你有两个活动的例外,你的程序abort()没有通过go(当然也没有触发任何剩余的析构函数)。

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. Java根本没有堆栈展开 - 如果抛出异常,它对对象不做任何事情。 You have to handle the objects yourself in catch and finally blocks. 你必须自己处理catchfinally块中的对象。 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. 这主要是为什么C#引入了using语句 - 它们简化了调用IDisposable.Dispose(),但同样不是C ++堆栈展开的完全替代。

你是完全正确的,C ++以相反的顺序销毁所有局部变量,因为它退出堆栈上的每个函数 - 就像你以编程方式执行return - 而不是main()

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. 在Java中,所有原始类型(int,double等)都直接保存,此时此类型的局部变量被释放。 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). 如果在C ++中是在堆上创建的对象并且局部变量保留指针,则堆上的对象不会自动释放,它们永远保留在堆上(是的,你得到一个MEMORY LEAK)。 If you have saved objects on the stack, then the destructor is called (and may release other referenced objects on the heap). 如果已在堆栈上保存了对象,则会调用析构函数(并且可能会释放堆上的其他引用对象)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM