问题
According to Oracle, a StackOverflowError is:
Thrown when a stack overflow occurs because an application recurses too deeply.
I know what recursion is and normally recursive functions, if not terminated properly, lead to StackOverflowError. To check the number of recursive calls that happen before StackOverflowError
is thrown, I wrote this code:
package ErrorCases;
public class StackOverFlowError {
static int i=0;
void a()
{
//System.out.println("called "+(++i));
try{
++i;
a();
}catch(Error e)
{
System.out.println(e.getClass());
System.out.println(i);
}
}
public static void main(String[] args) {
new StackOverFlowError().a();
}
}
the value of i
gives the count of recursive calls to a()
before JVM threw StackOverflowError.
The value of i
is different in every run like:
output 1: class java.lang.StackOverflowError
10466
Output 2: class java.lang.StackOverflowError
10470
My query is ?
How deep the recursion has to happen before JVM throws
StackOverflowError
?Can we recover once a
StackOverflowError
has been thrown?
回答1:
The depth depends on two things:
1: The size of the stack.
2: The amount of stack space used in each recursion.
Function parameters, local variables and the return address are all allocated on the stack while objects are allocated on the heap.
Recovery
It is possible to recover.
try {
myDeepRecursion();
} catch (StackOverflowError e) {
// We are back from deep recursion. Stack should be ok again.
}
However, note the following regarding errors (from the java API doc):
An Error is a subclass of Throwable that indicates serious problems that a reasonable application should not try to catch.
EDIT:
A note of caution: While catching exceptions inside a recursive function is ok, don't try to catch errors. If the stack is full, then the error handling will cause new errors. Simple things, such as a call to System.out.println()
will fail because there is no room left on the stack for the return address.
That is why errors should be caught outside the recursive function.
回答2:
How deep the recursion has to happen before JVM throws StackOverflowError?
It really depends on the machine you're working with and your JVM and its configuration. (it's 6000 - 8500 on my current setup with a lot of tasks in the background) and at most, the this you do in the application and the recursive method.
Can we recover once a StackOverflowError has been thrown?
No! I Java throws an error, there is no way back to normal. That is the main difference between Exceptions and Errors.
An Error is a subclass of Throwable that indicates serious problems that a reasonable application should not try to catch
Read more about Errors here
Read more about Java stack size myths here
Edit:
You can still do things after an error occurs, but does it make sense? You have a serious error in your code! You can't be sure that everything works correctly!
Your code is not terminating because you call the method again which is the same like an endless loop
回答3:
The reason why you may see different stack depths is that the stack frames are not necessarily the same size. The Hotspot JVM for example has different stack frames for JIT compiled code and for interpreted code. The JIT compiler works in parallel with the running code, so external factors like load on the machine may have an effect on when / if the JVM starts using JIT stack frames.
One thing that you should keep in mind is the fact that when you get a StackOverflowError
, almost anything that you do may cause another StackOverflowError
. For example printing the name of the error class in the catch
part may also run out of stack space, so another StackOverflowError
will be thrown down the stack.
Some people claim that you cannot recover from an Error
because the JVM is shutting down. That is not correct; you can recover from some errors. What's tricky about StackOverflowError
and OutOfMemoryError
is that once you catch one you have absolutely no guarantees of the state of the program; for example a key data structure you use might be in an inconsistent state. This makes recovery hard or impossible in general.
回答4:
Parameters and local variables are allocated on the stack (with reference types the object lives on the heap and a variable references that object). The stack typically lives at the upper end of your address space and as it is used up it heads towards the bottom of the address space (ie towards zero).
Your process also has a heap, which lives at the bottom end of your process. As you allocate memory this heap can grow towards the upper end of your address space. As you can see, there is the potential for the heap to "collide" with the stack (a bit like techtonic plates!!!). [source]
So the StackOIverflowError will depend on your stack size as well as your heap size which will depend from execution to execution because of lot of factors like GC.
Also as the name says it is Error and not Exception. There is no recovery from it. JVM will shut down.
来源:https://stackoverflow.com/questions/20658264/when-does-stackoverflowerror-occur