No-Throw Virtualmachineerror Guarantees

No-throw VirtualMachineError guarantees

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.

Which JVM instructions cannot throw?

You are asking the wrong question. If you expect a VirtualMachineError to be thrown, you can’t expect the behavior to be guaranteed to stay the same, regardless of whether there is a try … catch or not.

To stay at your example:

try { return 1; }
catch (Throwable t) { return 2; }

For this code, there will be an exception handler for the two byte code instructions iload_1, ireturn. This implies that if a VirtualMachineError is raised right before the iload_1 instruction or right after the JVM encountered the ireturn instruction, the error won’t be catched. And nobody can tell apart that situation from the situation when the the exception handler has been removed and the error is raised in-between these instructions.

Compare with The Java® Virtual Machine Specification, Java SE 8 Edition §2.10. Exceptions:

A Java Virtual Machine may permit a small but bounded amount of execution to occur before an asynchronous exception is thrown. This delay is permitted to allow optimized code to detect and throw these exceptions at points where it is practical to handle them while obeying the semantics of the Java programming language.

So for the case of the VirtualMachineError, the absence of the exception handler would make no difference, no one can notice it and the JVM might defer the error anyway depending on the internal state of code optimization. A different case is the possibility of ireturn throwing an IllegalMonitorStateException.

After all, the question is what you are going to optimize. Exception handlers normally have no performance impact as the JVM doesn’t touch them as long as no exception is there to be handled.

What operations may (not) throw StackOverflowError?

is it true that code which do not call any functions will never throw a java.lang.StackOverflowError?

A StackOverflowError is-a VirtualMachineError. It transpires that there are no no-throw guarantees about VirtualMachineErrors. The Java Virtual Machine Specification says the following (emphasis added).

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:
...
StackOverflowError

Which Java Errors and Exceptions may (not) be thrown by empty statements?

This question is very similar to the other question you posted. I think I'll try to address both questions here.

Since you refer to the JVMS I'll assume that you're after a formal answer, and the formal answer is that your question(s) doesn't really make sense. :-)

Asking how the JVM will execute a snippet of Java source code is like asking a mathematician the correct way of computing 10+10. The mathematician will probably say something like "how to compute it is not defined". Similarly, the JLS that defines the meaning of the Java snippet does not go into specifics of how to execute it.

So, first let me formalize your question slightly: "Where in the bytecode (emitted by the reference implementation of javac) corresponding to the given Java snippets could VirtualMachineErrors occur?"

This question is arguably much simpler to answer. The relevant section of the JVMS says

A Java Virtual Machine implementation throws an object that is an instance of a subclass of the class VirtualMethodError when an internal error or resource limitation prevents it from implementing the semantics described in this chapter. This specification cannot predict where internal errors or resource limitations may be encountered and does not mandate precisely when they can be reported.

Thus, the answer is: Between any two bytecode instructions.

Now to return to your original question: This snippet for instance

try {
// nothing
} catch (java.lang.Throwable e) {
// which Throwable subclass might we see?
}

is compiled to the empty program, which can't reasonably throw any exceptions.


Regarding your follow up question in a comment:

Should JLS 11.1.3 be read as "subclasses of Throwable are guaranteed not to appear between bytecode unless it is a subclass of VirtualMachineError"?

Yes, you could put it like that. I would perhaps have worded it a bit differently: Any instruction can give rise to

  • the exceptions specified by the JVM Instruction set for the instruction in question,
  • any exception of type VirtualMachineError
  • and no other exceptions

Get “Could not create the Java virtual machine” error running StarTeam 2008 Release 2 client

Rather than being a problem locating the Java Virtual Machine, as I’d previously thought, turns out it’s a memory allocation issue.

In StarTeamCP.stjava, the default option set is -Xmx1024m. My machine doesn’t have a gig of RAM to spare for a Java VM, hence the error.

By setting it to -Xmx512m, I was able to get up and running.

See also my blog entry about this.

Why is it possible to recover from a StackOverflowError?

When the stack overflows and StackOverflowError is thrown, the usual exception handling unwinds the stack. Unwinding the stack means:

  • abort the execution of the currently active function
  • delete its stack frame, proceed with the calling function
  • abort the execution of the caller
  • delete its stack frame, proceed with the calling function
  • and so on...

... until the exception is caught. This is normal (in fact, necessary) and independent of which exception is thrown and why. Since you catch the exception outside of the first call to foo(), the thousands of foo stack frames that filled the stack have all been unwound and most of the stack is free to be used again.

Can I prevent java from throwing certain exceptions?

A distinction must be drawn between checked and unchecked exceptions to answer this question:

  • If a method does not declare that it throws a checked exception, it cannot throw an exception of that type (or one of its subtypes):

    void doSomething() {
    throw new Exception(); // Illegal, without throws Exception on doSomething();
    }

    As such, you know that a checked exception is not thrown by a method if it is not declared throwing that exception.

    Checked exceptions are intended to be caught, since they are supposed to indicate conditions from which you can recover, so you need to know that they occurred. e.g. IOException: if you try again later, the file might exist, the disk might have space on it, the network might be back up (etc).

  • A method can throw an unchecked exception without declaring that it does; but similarly, you don't need to put in any work to catch it if you don't want to (e.g. because you know that it cannot possibly be thrown). As such, you can never guarantee that a particular RuntimeException is not thrown by a method - maybe it's not thrown directly by the method you called, but it could be thrown by a method that calls (now or in future implementations).

    Unchecked exceptions are not really intended to be caught, since they are supposed to indicate unrecoverable errors, like programming errors. e.g. NullPointerException: you can call the same method with the same parameters, but it'll still fail, because you're running the same code.



Related Topics



Leave a reply



Submit