No-throw VirtualMachineError guarantees
Asked Answered
F

4

15

I've come to Java from C++. In the C++ world we pay attention to exception safety, and note that mutators can provide different guarantees in the face of exceptions thrown by the mutator itself or a method it delegates to (minimum, strong, no-throw). Implementing a method that has a strong exception guarantee requires that some basic operations are guaranteed never to throw an exception. The JLS makes statements about which operations can throw which kinds of exceptions, but the VirtualMachineError error presents a problem. Quoth the JLS:

an internal error or resource limitation prevents the Java virtual machine from implementing the semantics of the Java programming language; in this case, an instance of a subclass of VirtualMachineError is thrown.

The JLS says no more about VirtualMachineError. An "internal error" means a bug in the JVM, so I'm not interested in that case: in the face of bugs in the JVM, all bets are off. But what about the "resource limitation" case? Are there any operations that are guaranteed never to fail because of a resource limitation?

Flirtation answered 4/1, 2012 at 14:56 Comment(2)
The closest thing to an answer would be try { ... } catch (Throwable t) { }. Of course if memory is exhausted any continuation will prove to be nearly impossible. Now that is not different in C++.Stint
I'm answering my own question. The FAQ even ecourages this.Flirtation
F
18

Quoth the Java Virtual Machine Specification:

This specification cannot predict where internal errors or resource limitations may be encountered and does not mandate precisely when they can be reported. Thus, any of the VirtualMachineError subclasses defined below may be thrown at any time during the operation of the Java virtual machine:

In Java therefore no exception guarantees can be made with respect to VirtualMachineError exceptions. All exception guarantees must be subject to the qualification "... but not if a VirtualMachineError is thrown". This is one of the ways in which Java is different from C++.

This also suggests that there is not much point in catching a VirtualMachineError exception, because the program is in an undefined state if one has been thrown. That unfortunately includes OutOfMemoryError exceptions. Unfortunate, because if a program has several independent tasks to perform (for example, a web server), if one task fails because it needs too much memory, we might want to continue with the other tasks.

Flirtation answered 4/1, 2012 at 15:5 Comment(5)
Are you answering your own question, or just adding to it?Zagazig
I am answering my own question.Flirtation
Both VirtualMachineError and OutOfMemoryError are Errors. Rather than just crash, Java throws an Error in some abnormal conditions. That said, none of the Error subclasses are intended to be caught by most programs. Errors can be distinguished from Exceptions, which may be caught. The exception guarantees promoted by Herb Sutter can be applied to Java as well, for normal Exceptions.Rikki
See also: #1692730Flirtation
See also: #3871778Flirtation
C
1

If it is resource limitation, on the first place, no operations takes place. Here is link for perfect example to have VirtualMachineError. Virtual machine error

This error is not something like OutofMemoryError, where by that time some operations might be in progress.

Carotid answered 4/1, 2012 at 15:10 Comment(2)
"no operations takes place". That would be the "strong exceptino guarantee". But no such guarantee is made.Flirtation
If my interpretation is correct, based on above example, before VM get initiated, it was checking for defined resources like -Xmx parameters and it couldn't find defined size of memory and throw error. I agree with your point on no guarantee made, but don't know why.Carotid
W
1

I see that you've answered your own question and I can understand why this would be mildly surprising to you, coming from a strict C++ background. This is just the reality of managed memory (virtual) machines and it's not limited to just java. Memory can run out, as the JVM is bounded to how much heap it can use (configurable on the java command line).

Somewhat analogous, but not equivalent, in the C++/machine-code world would be a GENERAL_PROTECTION_FAULT (or SEGMENTATION_FAULT if you're on *NIX) that you would get when attempting to address memory that has not been allocated or is outside your virtual address space. Providing a "strong exception guarantee" in the face of that scenario is equally difficult as the cause may be either a bug in code or completely outside the control of the program.

Wayworn answered 4/1, 2012 at 15:17 Comment(5)
A SEGV indicates a bug in the program. Its analogy in Java is NullPointerException.Flirtation
I do not see how this is a general feature of a managed virtual machine. The JVMS allows OutOfMemoryError to be thrown even when you are not using new or trying to load a class.Flirtation
@Flirtation you will only get a NPE when you try to reference null. You will only get OutOfMemoryError after you attempt to allocate more memory (or you call a method which does) and the GC has run and not enough memory is freed.Adaurd
"You will only get OutOfMemoryError after you attempt to allocate more memory" This is the intutive meaning: only you can cause it. But that is not what the JVMS says: the JVM may throw it any any time.Flirtation
Well, we're in to semantics here. OutOfMemoryError can be thrown at any time, that is correct. One of the most common occurrences of OutOfMemoryError is the "GC overhead limit exceeded" scenario, which is thrown when the GC is consuming an inordinate amount of CPU-time due to not being able to free enough memory in each pass. What is the chicken and egg, "new" or GC? GC triggering is non-deterministic, but trying to allocate memory (via "new") is definitely a strong incentive for it to run so while "new" may not be the immediate proximal cause, of course it's the root cause.Wayworn
A
0

In Java, you can call Thread.stop() or stop(Throwable) at any time. Most errors are considered so critical that you should not try to handle them unless you really know what you are doing.

Having developed server side Java application for 12 years, I can say I have never heard of anyone worrying about random exceptions being thrown. I suspect its just not an issue you need to worry about with Java.

Can you give an example of why you believe you need a guarantee, as there is likely to be another way to solve the problem?

Adaurd answered 4/1, 2012 at 15:19 Comment(4)
The OutOfMemoryError exception is the most interesting case. As I say in my own answer: Unfortunate, because if one of several tasks fails because it needs too much memory we might want to continue with the other tasks. But if the JVM can throw a OutOfMemoryError, we can not rely on our program being in a valid state when we catch a OutOfMemoryError. This makes a try-catch-discard approach unreliable.Flirtation
Added missing "NOT" before "try to handle them."Rikki
@Flirtation You are right that discarding the OOME is unreliable. What you have to do is define the maximum memory at which you would expect the whole JVM to fail (not just a soft limit) and avoid performing operations which could fail because you have no idea how much memory they use. In the worse case, you need to use a separate process which can be killed re-started as required. (This also protect against bug in JNI libraries)Adaurd
@PeterLawrey That sort of strategy is quite popular with apps like Google Chrome where all the heavy lifting is done in separate processes which somehow render back into the real window. It would be nice if there were a convenient way to do that sort of thing in Java. As it stands today in most apps, the GUI is handled by the EDT running in a single process and if something GUI-side hits an OOME (e.g. you try to sort a table which is too big), all you can do is catch it and hope that it didn't break some other thread doing important stuff.Vice

© 2022 - 2024 — McMap. All rights reserved.