The question is strictly theoretical but I couldn't find an answer. Consider this short program:
public class SBtst {
int i = 0;
public static void main(String[] args) {
new SBtst().rec();
}
public void rec() {
System.out.println("rec is called "+i++);
try {
rec();
} catch (StackOverflowError soe) {
System.out.println("completed "+soe.getStackTrace().length);
}
}
}
After execution I get output similar to:
rec is called 10472
rec is called 10473
rec is called 10474Recursion completed 1024
The questions are:
Why didn't println() completed new line because as I understand it, an error should be thrown when the next rec() call is executed and it is AFTER println() completed
Why do I get only 1024 elements in the stackTrace
array but i
is equal to 10474? Does it mean that not every call is in the stack trace?
Why didn't println() complete a new line? As I understand, the exception should be thrown when the next rec() call is executed, but that would be after println() has completed.
Your understanding isn't quite correct. At some point the stack looks like:
…
rec()
rec()
rec()
println()
Println consumes resources too (see mattingly890's answer), and there's no reason that you couldn't reach the limit at that point.
Why do I get only 1024 elements in the stack trace, even though at least 10474 were used? Does it mean that not every call is in the stack trace?
Have a look at the documentation for getStackTrace():
Provides programmatic access to the stack trace information printed by printStackTrace(). Returns an array of stack trace elements, each representing one stack frame. The zeroth element of the array (assuming the array's length is non-zero) represents the top of the stack, which is the last method invocation in the sequence. Typically, this is the point at which this throwable was created and thrown. The last element of the array (assuming the array's length is non-zero) represents the bottom of the stack, which is the first method invocation in the sequence.
Some virtual machines may, under some circumstances, omit one or more stack frames from the stack trace. In the extreme case, a virtual machine that has no stack trace information concerning this throwable is permitted to return a zero-length array from this method. Generally speaking, the array returned by this method will contain one element for every frame that would be printed by printStackTrace. Writes to the returned array do not affect future calls to this method.
In the comments Peter Lawrey found the documentation where the a 1024 default limit is mentioned for stack size:
Java HotSpot VM Options
-XX:ThreadStackSize=512
Thread Stack Size (in Kbytes). (0 means use default stack size) [Sparc: 512; Solaris x86: 320 (was 256 prior in 5.0 and earlier); Sparc 64 bit: 1024; Linux amd64: 1024 (was 0 in 5.0 and earlier); all others 0.]
There might be other factors that come into play, too, though. For instance, these questions mention two other options:
Part 1:
In the OpenJDK implementation, the println()
implementation looks like:
public void println(String x) {
synchronized (this) {
print(x);
newLine();
}
}
Thus, the call to print(x)
could overflow the stack, and the StackOverflowError
would be raised without the newLine()
method ever being called.
Part 2:
From the Java API:
Some virtual machines may, under some circumstances, omit one or more stack frames from the stack trace... Generally speaking, the array returned by this method will contain one element for every frame that would be printed by printStackTrace.
Thus, the JVM is free to impose a limit, such as 1024, on the number of stack frames stored in the stack trace.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With