StackOverflowError During Parallel Recursion [duplicate] - java

This question already has answers here:
What is a StackOverflowError?
(16 answers)
Closed 1 year ago.
I'm using a parallel recursion to evaluate if a number is odd or even. I used long type but I'm running into StackOverflowError when input number(x) has 5 digits or more. I don't get why.
static boolean Odd(long n) {
if (n == 0) return false;
else return Even(n - 1);
}
static boolean Even(long d) {
if (d == 0) return true;
else return Odd(d - 1);
}
public static void main(String[] args) {
long x = 0;
while(x>=0) {
System.out.println("Insert number");
x = SavitchIn.readLong();
boolean isOdd = Odd(x);
if(isOdd) {
System.out.println("Odd number");
}else {
System.out.println("Even number");
}
}
}

To understand why you get StackOverflowError, you need to understand what happens when you make a function call in your code and how that is executed in the actual processor.
When you run a program, all of the associated code and symbols are loaded in the memory and then executed one line after another. You have a register called Program Counter which basically acts as a pointer to the current line of code that is executed.
However, when the line to be executed is a function, the code for the function is not available immediately on the next memory address. Rather, this function will be available at a different location in memory. So when the processing unit sees a function call, it copies several important stats like the Program Counter [PC] (to know how far along the code has been executed), register values, etc., and pushes this data into a stack. The reason this data structure is a stack can be explained with the following simple code example:
public class Example {
public int func1() {
int a = 10, b = 20;
int c = a+b;
return c;
}
public int func2() {
int a = 100;
int b = func1();
return a*b;
}
public static void main(String args[]) {
int attr = 10;
int result = func2() / 10;
System.out.println(result);
}
}
In this example, as you know, code execution starts at ```main```` function. So line 1 of the main function is executed and sets the attr variable to 10. Then it goes to line 2 and here, it sees that there is a function call namely func2.
So at this time, the system will push the PC, and other memory into the stack, and then move to the location of func2. In func2, line 1 is executed setting the value of a to 100. Line 2 of func2 is again a function call and hence again all the data is now again pushed onto the stack on top of the previous push and func1 is executed.
In func1, we have no function calls and hence no more stack pushes happen. Func1 has 3 lines of code which get executed one after the other. However, just because we reached the end of func1, it does not mean that we have finished executing the code. We still have to execute the rest of func2 and main. The first set of code we need to execute is func2 because func2 called func1. This is exactly what we have in the stack as well (the top of the stack has func2 values). So we pop it, continue executing func2 and once that is done, we go back to the stack and see there is an entry from the main function. So we pop that out and complete execution.
Now that we have this bit of understanding, in your code, you see that the Odd() and Even() method call each other recursively. For a small number of 5, we see the following happening:
Main(
-push-> Odd(5
-push-> Even(4
-push-> Odd(3
-push-> Even(2
-push-> Odd(1
-push-> Even(0
[return's true]
) -pop->
) -pop->
) -pop->
) -pop->
) -pop->
) -pop->
)
So in this case, for a small number like 5, we see that the size of the stack goes as high as 6. Now for a 5 digit number like 99999, the maximum size of the stack will be 100000 which is an extremely large number for the stack. Remember that for every stack entry, we will be copying the PC, registers, etc. on the stack.
This is why you see a StackOverflowError for 5 digit numbers. The size of the stack becomes very high when the number of digits is 5 which is probably beyond the capabilities of the processor that is running your code.

Related

Exception in thread "AWT-EventQueue-0" java.lang.StackOverflowError and firePropertyChange [duplicate]

What is a StackOverflowError, what causes it, and how should I deal with them?
Parameters and local variables are allocated on the stack (with reference types, the object lives on the heap and a variable in the stack references that object on the heap). 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 (i.e. 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 a potential for the heap to "collide" with the stack (a bit like tectonic plates!!!).
The common cause for a stack overflow is a bad recursive call. Typically, this is caused when your recursive functions doesn't have the correct termination condition, so it ends up calling itself forever. Or when the termination condition is fine, it can be caused by requiring too many recursive calls before fulfilling it.
However, with GUI programming, it's possible to generate indirect recursion. For example, your app may be handling paint messages, and, whilst processing them, it may call a function that causes the system to send another paint message. Here you've not explicitly called yourself, but the OS/VM has done it for you.
To deal with them, you'll need to examine your code. If you've got functions that call themselves then check that you've got a terminating condition. If you have, then check that when calling the function you have at least modified one of the arguments, otherwise there'll be no visible change for the recursively called function and the terminating condition is useless. Also mind that your stack space can run out of memory before reaching a valid terminating condition, thus make sure your method can handle input values requiring more recursive calls.
If you've got no obvious recursive functions then check to see if you're calling any library functions that indirectly will cause your function to be called (like the implicit case above).
To describe this, first let us understand how local variables and objects are stored.
Local variable are stored on the stack:
If you looked at the image you should be able to understand how things are working.
When a function call is invoked by a Java application, a stack frame is allocated on the call stack. The stack frame contains the parameters of the invoked method, its local parameters, and the return address of the method. The return address denotes the execution point from which, the program execution shall continue after the invoked method returns. If there is no space for a new stack frame then, the StackOverflowError is thrown by the Java Virtual Machine (JVM).
The most common case that can possibly exhaust a Java application’s stack is recursion. In recursion, a method invokes itself during its execution. Recursion is considered as a powerful general-purpose programming technique, but it must be used with caution, to avoid StackOverflowError.
An example of throwing a StackOverflowError is shown below:
StackOverflowErrorExample.java:
public class StackOverflowErrorExample {
public static void recursivePrint(int num) {
System.out.println("Number: " + num);
if (num == 0)
return;
else
recursivePrint(++num);
}
public static void main(String[] args) {
StackOverflowErrorExample.recursivePrint(1);
}
}
In this example, we define a recursive method, called recursivePrint that prints an integer and then, calls itself, with the next successive integer as an argument. The recursion ends until we pass in 0 as a parameter. However, in our example, we passed in the parameter from 1 and its increasing followers, consequently, the recursion will never terminate.
A sample execution, using the -Xss1M flag that specifies the size of the thread stack to equal to 1 MB, is shown below:
Number: 1
Number: 2
Number: 3
...
Number: 6262
Number: 6263
Number: 6264
Number: 6265
Number: 6266
Exception in thread "main" java.lang.StackOverflowError
at java.io.PrintStream.write(PrintStream.java:480)
at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:221)
at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:291)
at sun.nio.cs.StreamEncoder.flushBuffer(StreamEncoder.java:104)
at java.io.OutputStreamWriter.flushBuffer(OutputStreamWriter.java:185)
at java.io.PrintStream.write(PrintStream.java:527)
at java.io.PrintStream.print(PrintStream.java:669)
at java.io.PrintStream.println(PrintStream.java:806)
at StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:4)
at StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:9)
at StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:9)
at StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:9)
...
Depending on the JVM’s initial configuration, the results may differ, but eventually the StackOverflowError shall be thrown. This example is a very good example of how recursion can cause problems, if not implemented with caution.
How to deal with the StackOverflowError
The simplest solution is to carefully inspect the stack trace and
detect the repeating pattern of line numbers. These line numbers
indicate the code being recursively called. Once you detect these
lines, you must carefully inspect your code and understand why the
recursion never terminates.
If you have verified that the recursion
is implemented correctly, you can increase the stack’s size, in
order to allow a larger number of invocations. Depending on the Java
Virtual Machine (JVM) installed, the default thread stack size may
equal to either 512 KB, or 1 MB. You can increase the thread stack
size using the -Xss flag. This flag can be specified either via the
project’s configuration, or via the command line. The format of the
-Xss argument is:
-Xss<size>[g|G|m|M|k|K]
If you have a function like:
int foo()
{
// more stuff
foo();
}
Then foo() will keep calling itself, getting deeper and deeper, and when the space used to keep track of what functions you're in is filled up, you get the stack overflow error.
Stack overflow means exactly that: a stack overflows. Usually there's a one stack in the program that contains local-scope variables and addresses where to return when execution of a routine ends. That stack tends to be a fixed memory range somewhere in the memory, therefore it's limited how much it can contain values.
If the stack is empty you can't pop, if you do you'll get stack underflow error.
If the stack is full you can't push, if you do you'll get stack overflow error.
So stack overflow appears where you allocate too much into the stack. For instance, in the mentioned recursion.
Some implementations optimize out some forms of recursions. Tail recursion in particular. Tail recursive routines are form of routines where the recursive call appears as a final thing what the routine does. Such routine call gets simply reduced into a jump.
Some implementations go so far as implement their own stacks for recursion, therefore they allow the recursion to continue until the system runs out of memory.
Easiest thing you could try would be to increase your stack size if you can. If you can't do that though, the second best thing would be to look whether there's something that clearly causes the stack overflow. Try it by printing something before and after the call into routine. This helps you to find out the failing routine.
A stack overflow is usually called by nesting function calls too deeply (especially easy when using recursion, i.e. a function that calls itself) or allocating a large amount of memory on the stack where using the heap would be more appropriate.
Like you say, you need to show some code. :-)
A stack overflow error usually happens when your function calls nest too deeply. See the Stack Overflow Code Golf thread for some examples of how this happens (though in the case of that question, the answers intentionally cause stack overflow).
A StackOverflowError is a runtime error in Java.
It is thrown when the amount of call stack memory allocated by the JVM is exceeded.
A common case of a StackOverflowError being thrown, is when the call stack exceeds due to excessive deep or infinite recursion.
Example:
public class Factorial {
public static int factorial(int n){
if(n == 1){
return 1;
}
else{
return n * factorial(n-1);
}
}
public static void main(String[] args){
System.out.println("Main method started");
int result = Factorial.factorial(-1);
System.out.println("Factorial ==>"+result);
System.out.println("Main method ended");
}
}
Stack trace:
Main method started
Exception in thread "main" java.lang.StackOverflowError
at com.program.stackoverflow.Factorial.factorial(Factorial.java:9)
at com.program.stackoverflow.Factorial.factorial(Factorial.java:9)
at com.program.stackoverflow.Factorial.factorial(Factorial.java:9)
In the above case, it can be avoided by doing programmatic changes.
But if the program logic is correct and it still occurs then your stack size needs to be increased.
StackOverflowError is to the stack as OutOfMemoryError is to the heap.
Unbounded recursive calls result in stack space being used up.
The following example produces StackOverflowError:
class StackOverflowDemo
{
public static void unboundedRecursiveCall() {
unboundedRecursiveCall();
}
public static void main(String[] args)
{
unboundedRecursiveCall();
}
}
StackOverflowError is avoidable if recursive calls are bounded to prevent the aggregate total of incomplete in-memory calls (in bytes) from exceeding the stack size (in bytes).
The most common cause of stack overflows is excessively deep or infinite recursion. If this is your problem, this tutorial about Java Recursion could help understand the problem.
Here is an example of a recursive algorithm for reversing a singly linked list. On a laptop (with the specifications 4 GB memory, Intel Core i5 2.3 GHz CPU 64 bit and Windows 7), this function will run into StackOverflow error for a linked list of size close to 10,000.
My point is that we should use recursion judiciously, always taking into account of the scale of the system.
Often recursion can be converted to iterative program, which scales better. (One iterative version of the same algorithm is given at the bottom of the page. It reverses a singly linked list of size 1 million in 9 milliseconds.)
private static LinkedListNode doReverseRecursively(LinkedListNode x, LinkedListNode first){
LinkedListNode second = first.next;
first.next = x;
if(second != null){
return doReverseRecursively(first, second);
}else{
return first;
}
}
public static LinkedListNode reverseRecursively(LinkedListNode head){
return doReverseRecursively(null, head);
}
Iterative Version of the Same Algorithm:
public static LinkedListNode reverseIteratively(LinkedListNode head){
return doReverseIteratively(null, head);
}
private static LinkedListNode doReverseIteratively(LinkedListNode x, LinkedListNode first) {
while (first != null) {
LinkedListNode second = first.next;
first.next = x;
x = first;
if (second == null) {
break;
} else {
first = second;
}
}
return first;
}
public static LinkedListNode reverseIteratively(LinkedListNode head){
return doReverseIteratively(null, head);
}
The stack has a space limit that depends on the operating system. The normal size is 8 MB (in Ubuntu (Linux), you can check that limit with $ ulimit -u and it can be checked in other OS similarly). Any program makes use of the stack at runtime, but to fully know when it is used you need to check the assembly language. In x86_64 for example, the stack is used to:
Save the return address when making a procedure call
Save local variables
Save special registers to restore them later
Pass arguments to a procedure call (more than 6)
Other: random unused stack base, canary values, padding, ... etc.
If you don't know x86_64 (normal case) you only need to know when the specific high-level programming language you are using compile to those actions. For example in C:
(1) → a function call
(2) → local variables in function calls (including main)
(3) → local variables in function calls (not main)
(4) → a function call
(5) → normally a function call, it is generally irrelevant for a stack overflow.
So, in C, only local variables and function calls make use of the stack. The two (unique?) ways of making a stack overflow are:
Declaring too large local variables in main or in any function that it's called in (int array[10000][10000];)
A very deep or infinite recursion (too many function calls at the same time).
To avoid a StackOverflowError you can:
check if local variables are too big (order of 1 MB) → use the heap (malloc/calloc calls) or global variables.
check for infinite recursion → you know what to do... correct it!
check for normal too deep recursion → the easiest approach is to just change the implementation to be iterative.
Notice also that global variables, include libraries, etc... don't make use of the stack.
Only if the above does not work, change the stack size to the maximum on the specific OS. With Ubuntu for example: ulimit -s 32768 (32 MB). (This has never been the solution for any of my stack overflow errors, but I also don't have much experience.)
I have omitted special and/or not standard cases in C (such as usage of alloc() and similar) because if you are using them you should already know exactly what you are doing.
In a crunch, the below situation will bring a stack overflow error.
public class Example3 {
public static void main(String[] args) {
main(new String[1]);
}
}
A simple Java example that causes java.lang.StackOverflowError because of a bad recursive call:
class Human {
Human(){
new Animal();
}
}
class Animal extends Human {
Animal(){
super();
}
}
public class Test01 {
public static void main(String[] args) {
new Animal();
}
}
Many answers to this question are good. However, I would like to take a slightly different approach and give some more insight into how memory works and also a (simplified) visualization to better understand StackOverflow errors. This understanding does not only apply to Java but all processes alike.
On modern systems all new processes get their own virtual address space (VAS). In essence VAS is an abstraction layer provided by the operating system on top of physical memory in order to ensure processes do not interfere with each others memory. It's the kernels job to then map the virtual addresses provided to to the actual physical addresses.
VAS can be divided into a couple of sections:
In order to let the CPU know what it is supposed to do machine instructions must be loaded into memory. This is usually referred to as the code or text segment and of static size.
On top of that one can find the data segment and heap. The data segment is of fixed size and contains global or static variables.
As a program runs into special conditions it may need to additionally allocate data, which is where the heap comes into play and is therefore able to dynamically grow in size.
The stack is located on the other side of the virtual address space and (among other things) keeps track of all function calls using a LIFO data structure. Similar to the heap a program may need additional space during runtime to keep track of new function calls being invoked. Since the stack is located on the other side of the VAS it is growing into the opposite direction i.e. towards the heap.
TL;DR
This is where the StackOverflow error comes into play.
Since the stack grows down (towards the heap) it may so happen that at some point in time it cannot grow further as it would overlap with the heap address space. Once that happens the StackOverflow error occurs.
The most common reason as to why this happens is due to a bug in the program making recursive calls that do not terminate properly.
Note that on some systems VAS may behave slightly different an can be divided into even more segments, however, this general understanding applies to all UNIX systems.
Here's an example
public static void main(String[] args) {
System.out.println(add5(1));
}
public static int add5(int a) {
return add5(a) + 5;
}
A StackOverflowError basically is when you try to do something, that most likely calls itself, and goes on for infinity (or until it gives a StackOverflowError).
add5(a) will call itself, and then call itself again, and so on.
This is a typical case of java.lang.StackOverflowError... The method is recursively calling itself with no exit in doubleValue(), floatValue(), etc.
File Rational.java
public class Rational extends Number implements Comparable<Rational> {
private int num;
private int denom;
public Rational(int num, int denom) {
this.num = num;
this.denom = denom;
}
public int compareTo(Rational r) {
if ((num / denom) - (r.num / r.denom) > 0) {
return +1;
} else if ((num / denom) - (r.num / r.denom) < 0) {
return -1;
}
return 0;
}
public Rational add(Rational r) {
return new Rational(num + r.num, denom + r.denom);
}
public Rational sub(Rational r) {
return new Rational(num - r.num, denom - r.denom);
}
public Rational mul(Rational r) {
return new Rational(num * r.num, denom * r.denom);
}
public Rational div(Rational r) {
return new Rational(num * r.denom, denom * r.num);
}
public int gcd(Rational r) {
int i = 1;
while (i != 0) {
i = denom % r.denom;
denom = r.denom;
r.denom = i;
}
return denom;
}
public String toString() {
String a = num + "/" + denom;
return a;
}
public double doubleValue() {
return (double) doubleValue();
}
public float floatValue() {
return (float) floatValue();
}
public int intValue() {
return (int) intValue();
}
public long longValue() {
return (long) longValue();
}
}
File Main.java
public class Main {
public static void main(String[] args) {
Rational a = new Rational(2, 4);
Rational b = new Rational(2, 6);
System.out.println(a + " + " + b + " = " + a.add(b));
System.out.println(a + " - " + b + " = " + a.sub(b));
System.out.println(a + " * " + b + " = " + a.mul(b));
System.out.println(a + " / " + b + " = " + a.div(b));
Rational[] arr = {new Rational(7, 1), new Rational(6, 1),
new Rational(5, 1), new Rational(4, 1),
new Rational(3, 1), new Rational(2, 1),
new Rational(1, 1), new Rational(1, 2),
new Rational(1, 3), new Rational(1, 4),
new Rational(1, 5), new Rational(1, 6),
new Rational(1, 7), new Rational(1, 8),
new Rational(1, 9), new Rational(0, 1)};
selectSort(arr);
for (int i = 0; i < arr.length - 1; ++i) {
if (arr[i].compareTo(arr[i + 1]) > 0) {
System.exit(1);
}
}
Number n = new Rational(3, 2);
System.out.println(n.doubleValue());
System.out.println(n.floatValue());
System.out.println(n.intValue());
System.out.println(n.longValue());
}
public static <T extends Comparable<? super T>> void selectSort(T[] array) {
T temp;
int mini;
for (int i = 0; i < array.length - 1; ++i) {
mini = i;
for (int j = i + 1; j < array.length; ++j) {
if (array[j].compareTo(array[mini]) < 0) {
mini = j;
}
}
if (i != mini) {
temp = array[i];
array[i] = array[mini];
array[mini] = temp;
}
}
}
}
Result
2/4 + 2/6 = 4/10
Exception in thread "main" java.lang.StackOverflowError
2/4 - 2/6 = 0/-2
at com.xetrasu.Rational.doubleValue(Rational.java:64)
2/4 * 2/6 = 4/24
at com.xetrasu.Rational.doubleValue(Rational.java:64)
2/4 / 2/6 = 12/8
at com.xetrasu.Rational.doubleValue(Rational.java:64)
at com.xetrasu.Rational.doubleValue(Rational.java:64)
at com.xetrasu.Rational.doubleValue(Rational.java:64)
at com.xetrasu.Rational.doubleValue(Rational.java:64)
at com.xetrasu.Rational.doubleValue(Rational.java:64)
Here is the source code of StackOverflowError in OpenJDK 7.

How should I decorate JSONObject? [duplicate]

What is a StackOverflowError, what causes it, and how should I deal with them?
Parameters and local variables are allocated on the stack (with reference types, the object lives on the heap and a variable in the stack references that object on the heap). 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 (i.e. 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 a potential for the heap to "collide" with the stack (a bit like tectonic plates!!!).
The common cause for a stack overflow is a bad recursive call. Typically, this is caused when your recursive functions doesn't have the correct termination condition, so it ends up calling itself forever. Or when the termination condition is fine, it can be caused by requiring too many recursive calls before fulfilling it.
However, with GUI programming, it's possible to generate indirect recursion. For example, your app may be handling paint messages, and, whilst processing them, it may call a function that causes the system to send another paint message. Here you've not explicitly called yourself, but the OS/VM has done it for you.
To deal with them, you'll need to examine your code. If you've got functions that call themselves then check that you've got a terminating condition. If you have, then check that when calling the function you have at least modified one of the arguments, otherwise there'll be no visible change for the recursively called function and the terminating condition is useless. Also mind that your stack space can run out of memory before reaching a valid terminating condition, thus make sure your method can handle input values requiring more recursive calls.
If you've got no obvious recursive functions then check to see if you're calling any library functions that indirectly will cause your function to be called (like the implicit case above).
To describe this, first let us understand how local variables and objects are stored.
Local variable are stored on the stack:
If you looked at the image you should be able to understand how things are working.
When a function call is invoked by a Java application, a stack frame is allocated on the call stack. The stack frame contains the parameters of the invoked method, its local parameters, and the return address of the method. The return address denotes the execution point from which, the program execution shall continue after the invoked method returns. If there is no space for a new stack frame then, the StackOverflowError is thrown by the Java Virtual Machine (JVM).
The most common case that can possibly exhaust a Java application’s stack is recursion. In recursion, a method invokes itself during its execution. Recursion is considered as a powerful general-purpose programming technique, but it must be used with caution, to avoid StackOverflowError.
An example of throwing a StackOverflowError is shown below:
StackOverflowErrorExample.java:
public class StackOverflowErrorExample {
public static void recursivePrint(int num) {
System.out.println("Number: " + num);
if (num == 0)
return;
else
recursivePrint(++num);
}
public static void main(String[] args) {
StackOverflowErrorExample.recursivePrint(1);
}
}
In this example, we define a recursive method, called recursivePrint that prints an integer and then, calls itself, with the next successive integer as an argument. The recursion ends until we pass in 0 as a parameter. However, in our example, we passed in the parameter from 1 and its increasing followers, consequently, the recursion will never terminate.
A sample execution, using the -Xss1M flag that specifies the size of the thread stack to equal to 1 MB, is shown below:
Number: 1
Number: 2
Number: 3
...
Number: 6262
Number: 6263
Number: 6264
Number: 6265
Number: 6266
Exception in thread "main" java.lang.StackOverflowError
at java.io.PrintStream.write(PrintStream.java:480)
at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:221)
at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:291)
at sun.nio.cs.StreamEncoder.flushBuffer(StreamEncoder.java:104)
at java.io.OutputStreamWriter.flushBuffer(OutputStreamWriter.java:185)
at java.io.PrintStream.write(PrintStream.java:527)
at java.io.PrintStream.print(PrintStream.java:669)
at java.io.PrintStream.println(PrintStream.java:806)
at StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:4)
at StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:9)
at StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:9)
at StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:9)
...
Depending on the JVM’s initial configuration, the results may differ, but eventually the StackOverflowError shall be thrown. This example is a very good example of how recursion can cause problems, if not implemented with caution.
How to deal with the StackOverflowError
The simplest solution is to carefully inspect the stack trace and
detect the repeating pattern of line numbers. These line numbers
indicate the code being recursively called. Once you detect these
lines, you must carefully inspect your code and understand why the
recursion never terminates.
If you have verified that the recursion
is implemented correctly, you can increase the stack’s size, in
order to allow a larger number of invocations. Depending on the Java
Virtual Machine (JVM) installed, the default thread stack size may
equal to either 512 KB, or 1 MB. You can increase the thread stack
size using the -Xss flag. This flag can be specified either via the
project’s configuration, or via the command line. The format of the
-Xss argument is:
-Xss<size>[g|G|m|M|k|K]
If you have a function like:
int foo()
{
// more stuff
foo();
}
Then foo() will keep calling itself, getting deeper and deeper, and when the space used to keep track of what functions you're in is filled up, you get the stack overflow error.
Stack overflow means exactly that: a stack overflows. Usually there's a one stack in the program that contains local-scope variables and addresses where to return when execution of a routine ends. That stack tends to be a fixed memory range somewhere in the memory, therefore it's limited how much it can contain values.
If the stack is empty you can't pop, if you do you'll get stack underflow error.
If the stack is full you can't push, if you do you'll get stack overflow error.
So stack overflow appears where you allocate too much into the stack. For instance, in the mentioned recursion.
Some implementations optimize out some forms of recursions. Tail recursion in particular. Tail recursive routines are form of routines where the recursive call appears as a final thing what the routine does. Such routine call gets simply reduced into a jump.
Some implementations go so far as implement their own stacks for recursion, therefore they allow the recursion to continue until the system runs out of memory.
Easiest thing you could try would be to increase your stack size if you can. If you can't do that though, the second best thing would be to look whether there's something that clearly causes the stack overflow. Try it by printing something before and after the call into routine. This helps you to find out the failing routine.
A stack overflow is usually called by nesting function calls too deeply (especially easy when using recursion, i.e. a function that calls itself) or allocating a large amount of memory on the stack where using the heap would be more appropriate.
Like you say, you need to show some code. :-)
A stack overflow error usually happens when your function calls nest too deeply. See the Stack Overflow Code Golf thread for some examples of how this happens (though in the case of that question, the answers intentionally cause stack overflow).
A StackOverflowError is a runtime error in Java.
It is thrown when the amount of call stack memory allocated by the JVM is exceeded.
A common case of a StackOverflowError being thrown, is when the call stack exceeds due to excessive deep or infinite recursion.
Example:
public class Factorial {
public static int factorial(int n){
if(n == 1){
return 1;
}
else{
return n * factorial(n-1);
}
}
public static void main(String[] args){
System.out.println("Main method started");
int result = Factorial.factorial(-1);
System.out.println("Factorial ==>"+result);
System.out.println("Main method ended");
}
}
Stack trace:
Main method started
Exception in thread "main" java.lang.StackOverflowError
at com.program.stackoverflow.Factorial.factorial(Factorial.java:9)
at com.program.stackoverflow.Factorial.factorial(Factorial.java:9)
at com.program.stackoverflow.Factorial.factorial(Factorial.java:9)
In the above case, it can be avoided by doing programmatic changes.
But if the program logic is correct and it still occurs then your stack size needs to be increased.
StackOverflowError is to the stack as OutOfMemoryError is to the heap.
Unbounded recursive calls result in stack space being used up.
The following example produces StackOverflowError:
class StackOverflowDemo
{
public static void unboundedRecursiveCall() {
unboundedRecursiveCall();
}
public static void main(String[] args)
{
unboundedRecursiveCall();
}
}
StackOverflowError is avoidable if recursive calls are bounded to prevent the aggregate total of incomplete in-memory calls (in bytes) from exceeding the stack size (in bytes).
The most common cause of stack overflows is excessively deep or infinite recursion. If this is your problem, this tutorial about Java Recursion could help understand the problem.
Here is an example of a recursive algorithm for reversing a singly linked list. On a laptop (with the specifications 4 GB memory, Intel Core i5 2.3 GHz CPU 64 bit and Windows 7), this function will run into StackOverflow error for a linked list of size close to 10,000.
My point is that we should use recursion judiciously, always taking into account of the scale of the system.
Often recursion can be converted to iterative program, which scales better. (One iterative version of the same algorithm is given at the bottom of the page. It reverses a singly linked list of size 1 million in 9 milliseconds.)
private static LinkedListNode doReverseRecursively(LinkedListNode x, LinkedListNode first){
LinkedListNode second = first.next;
first.next = x;
if(second != null){
return doReverseRecursively(first, second);
}else{
return first;
}
}
public static LinkedListNode reverseRecursively(LinkedListNode head){
return doReverseRecursively(null, head);
}
Iterative Version of the Same Algorithm:
public static LinkedListNode reverseIteratively(LinkedListNode head){
return doReverseIteratively(null, head);
}
private static LinkedListNode doReverseIteratively(LinkedListNode x, LinkedListNode first) {
while (first != null) {
LinkedListNode second = first.next;
first.next = x;
x = first;
if (second == null) {
break;
} else {
first = second;
}
}
return first;
}
public static LinkedListNode reverseIteratively(LinkedListNode head){
return doReverseIteratively(null, head);
}
The stack has a space limit that depends on the operating system. The normal size is 8 MB (in Ubuntu (Linux), you can check that limit with $ ulimit -u and it can be checked in other OS similarly). Any program makes use of the stack at runtime, but to fully know when it is used you need to check the assembly language. In x86_64 for example, the stack is used to:
Save the return address when making a procedure call
Save local variables
Save special registers to restore them later
Pass arguments to a procedure call (more than 6)
Other: random unused stack base, canary values, padding, ... etc.
If you don't know x86_64 (normal case) you only need to know when the specific high-level programming language you are using compile to those actions. For example in C:
(1) → a function call
(2) → local variables in function calls (including main)
(3) → local variables in function calls (not main)
(4) → a function call
(5) → normally a function call, it is generally irrelevant for a stack overflow.
So, in C, only local variables and function calls make use of the stack. The two (unique?) ways of making a stack overflow are:
Declaring too large local variables in main or in any function that it's called in (int array[10000][10000];)
A very deep or infinite recursion (too many function calls at the same time).
To avoid a StackOverflowError you can:
check if local variables are too big (order of 1 MB) → use the heap (malloc/calloc calls) or global variables.
check for infinite recursion → you know what to do... correct it!
check for normal too deep recursion → the easiest approach is to just change the implementation to be iterative.
Notice also that global variables, include libraries, etc... don't make use of the stack.
Only if the above does not work, change the stack size to the maximum on the specific OS. With Ubuntu for example: ulimit -s 32768 (32 MB). (This has never been the solution for any of my stack overflow errors, but I also don't have much experience.)
I have omitted special and/or not standard cases in C (such as usage of alloc() and similar) because if you are using them you should already know exactly what you are doing.
In a crunch, the below situation will bring a stack overflow error.
public class Example3 {
public static void main(String[] args) {
main(new String[1]);
}
}
A simple Java example that causes java.lang.StackOverflowError because of a bad recursive call:
class Human {
Human(){
new Animal();
}
}
class Animal extends Human {
Animal(){
super();
}
}
public class Test01 {
public static void main(String[] args) {
new Animal();
}
}
Many answers to this question are good. However, I would like to take a slightly different approach and give some more insight into how memory works and also a (simplified) visualization to better understand StackOverflow errors. This understanding does not only apply to Java but all processes alike.
On modern systems all new processes get their own virtual address space (VAS). In essence VAS is an abstraction layer provided by the operating system on top of physical memory in order to ensure processes do not interfere with each others memory. It's the kernels job to then map the virtual addresses provided to to the actual physical addresses.
VAS can be divided into a couple of sections:
In order to let the CPU know what it is supposed to do machine instructions must be loaded into memory. This is usually referred to as the code or text segment and of static size.
On top of that one can find the data segment and heap. The data segment is of fixed size and contains global or static variables.
As a program runs into special conditions it may need to additionally allocate data, which is where the heap comes into play and is therefore able to dynamically grow in size.
The stack is located on the other side of the virtual address space and (among other things) keeps track of all function calls using a LIFO data structure. Similar to the heap a program may need additional space during runtime to keep track of new function calls being invoked. Since the stack is located on the other side of the VAS it is growing into the opposite direction i.e. towards the heap.
TL;DR
This is where the StackOverflow error comes into play.
Since the stack grows down (towards the heap) it may so happen that at some point in time it cannot grow further as it would overlap with the heap address space. Once that happens the StackOverflow error occurs.
The most common reason as to why this happens is due to a bug in the program making recursive calls that do not terminate properly.
Note that on some systems VAS may behave slightly different an can be divided into even more segments, however, this general understanding applies to all UNIX systems.
Here's an example
public static void main(String[] args) {
System.out.println(add5(1));
}
public static int add5(int a) {
return add5(a) + 5;
}
A StackOverflowError basically is when you try to do something, that most likely calls itself, and goes on for infinity (or until it gives a StackOverflowError).
add5(a) will call itself, and then call itself again, and so on.
This is a typical case of java.lang.StackOverflowError... The method is recursively calling itself with no exit in doubleValue(), floatValue(), etc.
File Rational.java
public class Rational extends Number implements Comparable<Rational> {
private int num;
private int denom;
public Rational(int num, int denom) {
this.num = num;
this.denom = denom;
}
public int compareTo(Rational r) {
if ((num / denom) - (r.num / r.denom) > 0) {
return +1;
} else if ((num / denom) - (r.num / r.denom) < 0) {
return -1;
}
return 0;
}
public Rational add(Rational r) {
return new Rational(num + r.num, denom + r.denom);
}
public Rational sub(Rational r) {
return new Rational(num - r.num, denom - r.denom);
}
public Rational mul(Rational r) {
return new Rational(num * r.num, denom * r.denom);
}
public Rational div(Rational r) {
return new Rational(num * r.denom, denom * r.num);
}
public int gcd(Rational r) {
int i = 1;
while (i != 0) {
i = denom % r.denom;
denom = r.denom;
r.denom = i;
}
return denom;
}
public String toString() {
String a = num + "/" + denom;
return a;
}
public double doubleValue() {
return (double) doubleValue();
}
public float floatValue() {
return (float) floatValue();
}
public int intValue() {
return (int) intValue();
}
public long longValue() {
return (long) longValue();
}
}
File Main.java
public class Main {
public static void main(String[] args) {
Rational a = new Rational(2, 4);
Rational b = new Rational(2, 6);
System.out.println(a + " + " + b + " = " + a.add(b));
System.out.println(a + " - " + b + " = " + a.sub(b));
System.out.println(a + " * " + b + " = " + a.mul(b));
System.out.println(a + " / " + b + " = " + a.div(b));
Rational[] arr = {new Rational(7, 1), new Rational(6, 1),
new Rational(5, 1), new Rational(4, 1),
new Rational(3, 1), new Rational(2, 1),
new Rational(1, 1), new Rational(1, 2),
new Rational(1, 3), new Rational(1, 4),
new Rational(1, 5), new Rational(1, 6),
new Rational(1, 7), new Rational(1, 8),
new Rational(1, 9), new Rational(0, 1)};
selectSort(arr);
for (int i = 0; i < arr.length - 1; ++i) {
if (arr[i].compareTo(arr[i + 1]) > 0) {
System.exit(1);
}
}
Number n = new Rational(3, 2);
System.out.println(n.doubleValue());
System.out.println(n.floatValue());
System.out.println(n.intValue());
System.out.println(n.longValue());
}
public static <T extends Comparable<? super T>> void selectSort(T[] array) {
T temp;
int mini;
for (int i = 0; i < array.length - 1; ++i) {
mini = i;
for (int j = i + 1; j < array.length; ++j) {
if (array[j].compareTo(array[mini]) < 0) {
mini = j;
}
}
if (i != mini) {
temp = array[i];
array[i] = array[mini];
array[mini] = temp;
}
}
}
}
Result
2/4 + 2/6 = 4/10
Exception in thread "main" java.lang.StackOverflowError
2/4 - 2/6 = 0/-2
at com.xetrasu.Rational.doubleValue(Rational.java:64)
2/4 * 2/6 = 4/24
at com.xetrasu.Rational.doubleValue(Rational.java:64)
2/4 / 2/6 = 12/8
at com.xetrasu.Rational.doubleValue(Rational.java:64)
at com.xetrasu.Rational.doubleValue(Rational.java:64)
at com.xetrasu.Rational.doubleValue(Rational.java:64)
at com.xetrasu.Rational.doubleValue(Rational.java:64)
at com.xetrasu.Rational.doubleValue(Rational.java:64)
Here is the source code of StackOverflowError in OpenJDK 7.

How does the return keyword really work?

A simple code snippet calculating the factorial of a number below:
public class Main{
static int factorial(int number){
System.out.println("At factorial("+number+")");
if (number == 1){
return 1;
}
return number * factorial(number-1);
}
public static void main(String[] args){
System.out.println("factorial(4) = "+ factorial(4));
}
}
Here, I thought that when the value of the number becomes 1(due to recursion), it returns 1 every time and breaks out of the method and prints 1. But, it does return proper factorial value?
As per this: Java - Does returning a value break a loop?, shouldn't it have returned 1 every time? How these 2 code snippet differ in returning a value?
Thank You
I have tried to explain the whole process; refer to this source.
Prior to this you should have basic understanding of call stacks, recursion, and stack frames.
A call stack is a data structure used by the program to store information about the active subroutines. The main reason for having a call stack is so that the program can keep track of where a subroutine should return control to once it finishes executing.
A stack frame is a part of the call stack, and a new stack frame is created every time a subroutine is called. So, in our recursive factorial() method above, a new stack frame is created every time the method is called. The stack frame is used to store all of the variables for one invocation of a routine. So, remember that a call stack is basically a stack of stack frames.
Let's divide the process into 4 parts, since the number chosen is 4.
1st Iteration
static int factorial(4){
if (4 == 1){
return 1;
}
return 4 * factorial(3);
}
2nd Iteration
static int factorial(3){
if (3 == 1){
return 1;
}
return 3 * factorial(2);
}
3rd Iteration
static int factorial(2){
if (2 == 1){
return 1;
}
return 2 * factorial(1);
}
4th Iteration
static int factorial(1){
if (1 == 1){
return 1;
}
return 2 * factorial(number-1);
}
You can see that the first stack frame is created with a number equal to 4.
Then a call to factorial(3) is made – so the first call to factorial(4) does not run to completion because another call (factorial(3)) is made before the very first call to factorial can run to completion.
Same is the case for others.
A stack frame is used to hold the state of the first call to factorial(). It stores the local function variables (and their values) of the current invocation of factorial(), and it will also store the return address of the method that called it (since we are talking about the very first non-recursive invocation of factorial(), whatever routine invoked factorial() in the first place is where Factorial would return when it is completely done with everything).
Because the stack frame also stores the return address, the factorial() function knows where to return to when it finishes running
Process Execution
Finally, in the 4th stack frame, we run into our base case, which
means the recursive calls are finished and then control is returned to
the 3rd stack frame, where factorial(1) * 2 is calculated to be
2, and then control is returned to the 2nd stack frame where factorial(2) * 3 is calculated to be 6, and then control is
returned to the 1st stack frame where factorial(3) * 4 is
calculated to be 24. Finally, our result of 24 is returned.

Can an infinite loop cause a StackOverflow Exception in Java [duplicate]

What is a StackOverflowError, what causes it, and how should I deal with them?
Parameters and local variables are allocated on the stack (with reference types, the object lives on the heap and a variable in the stack references that object on the heap). 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 (i.e. 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 a potential for the heap to "collide" with the stack (a bit like tectonic plates!!!).
The common cause for a stack overflow is a bad recursive call. Typically, this is caused when your recursive functions doesn't have the correct termination condition, so it ends up calling itself forever. Or when the termination condition is fine, it can be caused by requiring too many recursive calls before fulfilling it.
However, with GUI programming, it's possible to generate indirect recursion. For example, your app may be handling paint messages, and, whilst processing them, it may call a function that causes the system to send another paint message. Here you've not explicitly called yourself, but the OS/VM has done it for you.
To deal with them, you'll need to examine your code. If you've got functions that call themselves then check that you've got a terminating condition. If you have, then check that when calling the function you have at least modified one of the arguments, otherwise there'll be no visible change for the recursively called function and the terminating condition is useless. Also mind that your stack space can run out of memory before reaching a valid terminating condition, thus make sure your method can handle input values requiring more recursive calls.
If you've got no obvious recursive functions then check to see if you're calling any library functions that indirectly will cause your function to be called (like the implicit case above).
To describe this, first let us understand how local variables and objects are stored.
Local variable are stored on the stack:
If you looked at the image you should be able to understand how things are working.
When a function call is invoked by a Java application, a stack frame is allocated on the call stack. The stack frame contains the parameters of the invoked method, its local parameters, and the return address of the method. The return address denotes the execution point from which, the program execution shall continue after the invoked method returns. If there is no space for a new stack frame then, the StackOverflowError is thrown by the Java Virtual Machine (JVM).
The most common case that can possibly exhaust a Java application’s stack is recursion. In recursion, a method invokes itself during its execution. Recursion is considered as a powerful general-purpose programming technique, but it must be used with caution, to avoid StackOverflowError.
An example of throwing a StackOverflowError is shown below:
StackOverflowErrorExample.java:
public class StackOverflowErrorExample {
public static void recursivePrint(int num) {
System.out.println("Number: " + num);
if (num == 0)
return;
else
recursivePrint(++num);
}
public static void main(String[] args) {
StackOverflowErrorExample.recursivePrint(1);
}
}
In this example, we define a recursive method, called recursivePrint that prints an integer and then, calls itself, with the next successive integer as an argument. The recursion ends until we pass in 0 as a parameter. However, in our example, we passed in the parameter from 1 and its increasing followers, consequently, the recursion will never terminate.
A sample execution, using the -Xss1M flag that specifies the size of the thread stack to equal to 1 MB, is shown below:
Number: 1
Number: 2
Number: 3
...
Number: 6262
Number: 6263
Number: 6264
Number: 6265
Number: 6266
Exception in thread "main" java.lang.StackOverflowError
at java.io.PrintStream.write(PrintStream.java:480)
at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:221)
at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:291)
at sun.nio.cs.StreamEncoder.flushBuffer(StreamEncoder.java:104)
at java.io.OutputStreamWriter.flushBuffer(OutputStreamWriter.java:185)
at java.io.PrintStream.write(PrintStream.java:527)
at java.io.PrintStream.print(PrintStream.java:669)
at java.io.PrintStream.println(PrintStream.java:806)
at StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:4)
at StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:9)
at StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:9)
at StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:9)
...
Depending on the JVM’s initial configuration, the results may differ, but eventually the StackOverflowError shall be thrown. This example is a very good example of how recursion can cause problems, if not implemented with caution.
How to deal with the StackOverflowError
The simplest solution is to carefully inspect the stack trace and
detect the repeating pattern of line numbers. These line numbers
indicate the code being recursively called. Once you detect these
lines, you must carefully inspect your code and understand why the
recursion never terminates.
If you have verified that the recursion
is implemented correctly, you can increase the stack’s size, in
order to allow a larger number of invocations. Depending on the Java
Virtual Machine (JVM) installed, the default thread stack size may
equal to either 512 KB, or 1 MB. You can increase the thread stack
size using the -Xss flag. This flag can be specified either via the
project’s configuration, or via the command line. The format of the
-Xss argument is:
-Xss<size>[g|G|m|M|k|K]
If you have a function like:
int foo()
{
// more stuff
foo();
}
Then foo() will keep calling itself, getting deeper and deeper, and when the space used to keep track of what functions you're in is filled up, you get the stack overflow error.
Stack overflow means exactly that: a stack overflows. Usually there's a one stack in the program that contains local-scope variables and addresses where to return when execution of a routine ends. That stack tends to be a fixed memory range somewhere in the memory, therefore it's limited how much it can contain values.
If the stack is empty you can't pop, if you do you'll get stack underflow error.
If the stack is full you can't push, if you do you'll get stack overflow error.
So stack overflow appears where you allocate too much into the stack. For instance, in the mentioned recursion.
Some implementations optimize out some forms of recursions. Tail recursion in particular. Tail recursive routines are form of routines where the recursive call appears as a final thing what the routine does. Such routine call gets simply reduced into a jump.
Some implementations go so far as implement their own stacks for recursion, therefore they allow the recursion to continue until the system runs out of memory.
Easiest thing you could try would be to increase your stack size if you can. If you can't do that though, the second best thing would be to look whether there's something that clearly causes the stack overflow. Try it by printing something before and after the call into routine. This helps you to find out the failing routine.
A stack overflow is usually called by nesting function calls too deeply (especially easy when using recursion, i.e. a function that calls itself) or allocating a large amount of memory on the stack where using the heap would be more appropriate.
Like you say, you need to show some code. :-)
A stack overflow error usually happens when your function calls nest too deeply. See the Stack Overflow Code Golf thread for some examples of how this happens (though in the case of that question, the answers intentionally cause stack overflow).
A StackOverflowError is a runtime error in Java.
It is thrown when the amount of call stack memory allocated by the JVM is exceeded.
A common case of a StackOverflowError being thrown, is when the call stack exceeds due to excessive deep or infinite recursion.
Example:
public class Factorial {
public static int factorial(int n){
if(n == 1){
return 1;
}
else{
return n * factorial(n-1);
}
}
public static void main(String[] args){
System.out.println("Main method started");
int result = Factorial.factorial(-1);
System.out.println("Factorial ==>"+result);
System.out.println("Main method ended");
}
}
Stack trace:
Main method started
Exception in thread "main" java.lang.StackOverflowError
at com.program.stackoverflow.Factorial.factorial(Factorial.java:9)
at com.program.stackoverflow.Factorial.factorial(Factorial.java:9)
at com.program.stackoverflow.Factorial.factorial(Factorial.java:9)
In the above case, it can be avoided by doing programmatic changes.
But if the program logic is correct and it still occurs then your stack size needs to be increased.
StackOverflowError is to the stack as OutOfMemoryError is to the heap.
Unbounded recursive calls result in stack space being used up.
The following example produces StackOverflowError:
class StackOverflowDemo
{
public static void unboundedRecursiveCall() {
unboundedRecursiveCall();
}
public static void main(String[] args)
{
unboundedRecursiveCall();
}
}
StackOverflowError is avoidable if recursive calls are bounded to prevent the aggregate total of incomplete in-memory calls (in bytes) from exceeding the stack size (in bytes).
The most common cause of stack overflows is excessively deep or infinite recursion. If this is your problem, this tutorial about Java Recursion could help understand the problem.
Here is an example of a recursive algorithm for reversing a singly linked list. On a laptop (with the specifications 4 GB memory, Intel Core i5 2.3 GHz CPU 64 bit and Windows 7), this function will run into StackOverflow error for a linked list of size close to 10,000.
My point is that we should use recursion judiciously, always taking into account of the scale of the system.
Often recursion can be converted to iterative program, which scales better. (One iterative version of the same algorithm is given at the bottom of the page. It reverses a singly linked list of size 1 million in 9 milliseconds.)
private static LinkedListNode doReverseRecursively(LinkedListNode x, LinkedListNode first){
LinkedListNode second = first.next;
first.next = x;
if(second != null){
return doReverseRecursively(first, second);
}else{
return first;
}
}
public static LinkedListNode reverseRecursively(LinkedListNode head){
return doReverseRecursively(null, head);
}
Iterative Version of the Same Algorithm:
public static LinkedListNode reverseIteratively(LinkedListNode head){
return doReverseIteratively(null, head);
}
private static LinkedListNode doReverseIteratively(LinkedListNode x, LinkedListNode first) {
while (first != null) {
LinkedListNode second = first.next;
first.next = x;
x = first;
if (second == null) {
break;
} else {
first = second;
}
}
return first;
}
public static LinkedListNode reverseIteratively(LinkedListNode head){
return doReverseIteratively(null, head);
}
The stack has a space limit that depends on the operating system. The normal size is 8 MB (in Ubuntu (Linux), you can check that limit with $ ulimit -u and it can be checked in other OS similarly). Any program makes use of the stack at runtime, but to fully know when it is used you need to check the assembly language. In x86_64 for example, the stack is used to:
Save the return address when making a procedure call
Save local variables
Save special registers to restore them later
Pass arguments to a procedure call (more than 6)
Other: random unused stack base, canary values, padding, ... etc.
If you don't know x86_64 (normal case) you only need to know when the specific high-level programming language you are using compile to those actions. For example in C:
(1) → a function call
(2) → local variables in function calls (including main)
(3) → local variables in function calls (not main)
(4) → a function call
(5) → normally a function call, it is generally irrelevant for a stack overflow.
So, in C, only local variables and function calls make use of the stack. The two (unique?) ways of making a stack overflow are:
Declaring too large local variables in main or in any function that it's called in (int array[10000][10000];)
A very deep or infinite recursion (too many function calls at the same time).
To avoid a StackOverflowError you can:
check if local variables are too big (order of 1 MB) → use the heap (malloc/calloc calls) or global variables.
check for infinite recursion → you know what to do... correct it!
check for normal too deep recursion → the easiest approach is to just change the implementation to be iterative.
Notice also that global variables, include libraries, etc... don't make use of the stack.
Only if the above does not work, change the stack size to the maximum on the specific OS. With Ubuntu for example: ulimit -s 32768 (32 MB). (This has never been the solution for any of my stack overflow errors, but I also don't have much experience.)
I have omitted special and/or not standard cases in C (such as usage of alloc() and similar) because if you are using them you should already know exactly what you are doing.
In a crunch, the below situation will bring a stack overflow error.
public class Example3 {
public static void main(String[] args) {
main(new String[1]);
}
}
A simple Java example that causes java.lang.StackOverflowError because of a bad recursive call:
class Human {
Human(){
new Animal();
}
}
class Animal extends Human {
Animal(){
super();
}
}
public class Test01 {
public static void main(String[] args) {
new Animal();
}
}
Many answers to this question are good. However, I would like to take a slightly different approach and give some more insight into how memory works and also a (simplified) visualization to better understand StackOverflow errors. This understanding does not only apply to Java but all processes alike.
On modern systems all new processes get their own virtual address space (VAS). In essence VAS is an abstraction layer provided by the operating system on top of physical memory in order to ensure processes do not interfere with each others memory. It's the kernels job to then map the virtual addresses provided to to the actual physical addresses.
VAS can be divided into a couple of sections:
In order to let the CPU know what it is supposed to do machine instructions must be loaded into memory. This is usually referred to as the code or text segment and of static size.
On top of that one can find the data segment and heap. The data segment is of fixed size and contains global or static variables.
As a program runs into special conditions it may need to additionally allocate data, which is where the heap comes into play and is therefore able to dynamically grow in size.
The stack is located on the other side of the virtual address space and (among other things) keeps track of all function calls using a LIFO data structure. Similar to the heap a program may need additional space during runtime to keep track of new function calls being invoked. Since the stack is located on the other side of the VAS it is growing into the opposite direction i.e. towards the heap.
TL;DR
This is where the StackOverflow error comes into play.
Since the stack grows down (towards the heap) it may so happen that at some point in time it cannot grow further as it would overlap with the heap address space. Once that happens the StackOverflow error occurs.
The most common reason as to why this happens is due to a bug in the program making recursive calls that do not terminate properly.
Note that on some systems VAS may behave slightly different an can be divided into even more segments, however, this general understanding applies to all UNIX systems.
Here's an example
public static void main(String[] args) {
System.out.println(add5(1));
}
public static int add5(int a) {
return add5(a) + 5;
}
A StackOverflowError basically is when you try to do something, that most likely calls itself, and goes on for infinity (or until it gives a StackOverflowError).
add5(a) will call itself, and then call itself again, and so on.
This is a typical case of java.lang.StackOverflowError... The method is recursively calling itself with no exit in doubleValue(), floatValue(), etc.
File Rational.java
public class Rational extends Number implements Comparable<Rational> {
private int num;
private int denom;
public Rational(int num, int denom) {
this.num = num;
this.denom = denom;
}
public int compareTo(Rational r) {
if ((num / denom) - (r.num / r.denom) > 0) {
return +1;
} else if ((num / denom) - (r.num / r.denom) < 0) {
return -1;
}
return 0;
}
public Rational add(Rational r) {
return new Rational(num + r.num, denom + r.denom);
}
public Rational sub(Rational r) {
return new Rational(num - r.num, denom - r.denom);
}
public Rational mul(Rational r) {
return new Rational(num * r.num, denom * r.denom);
}
public Rational div(Rational r) {
return new Rational(num * r.denom, denom * r.num);
}
public int gcd(Rational r) {
int i = 1;
while (i != 0) {
i = denom % r.denom;
denom = r.denom;
r.denom = i;
}
return denom;
}
public String toString() {
String a = num + "/" + denom;
return a;
}
public double doubleValue() {
return (double) doubleValue();
}
public float floatValue() {
return (float) floatValue();
}
public int intValue() {
return (int) intValue();
}
public long longValue() {
return (long) longValue();
}
}
File Main.java
public class Main {
public static void main(String[] args) {
Rational a = new Rational(2, 4);
Rational b = new Rational(2, 6);
System.out.println(a + " + " + b + " = " + a.add(b));
System.out.println(a + " - " + b + " = " + a.sub(b));
System.out.println(a + " * " + b + " = " + a.mul(b));
System.out.println(a + " / " + b + " = " + a.div(b));
Rational[] arr = {new Rational(7, 1), new Rational(6, 1),
new Rational(5, 1), new Rational(4, 1),
new Rational(3, 1), new Rational(2, 1),
new Rational(1, 1), new Rational(1, 2),
new Rational(1, 3), new Rational(1, 4),
new Rational(1, 5), new Rational(1, 6),
new Rational(1, 7), new Rational(1, 8),
new Rational(1, 9), new Rational(0, 1)};
selectSort(arr);
for (int i = 0; i < arr.length - 1; ++i) {
if (arr[i].compareTo(arr[i + 1]) > 0) {
System.exit(1);
}
}
Number n = new Rational(3, 2);
System.out.println(n.doubleValue());
System.out.println(n.floatValue());
System.out.println(n.intValue());
System.out.println(n.longValue());
}
public static <T extends Comparable<? super T>> void selectSort(T[] array) {
T temp;
int mini;
for (int i = 0; i < array.length - 1; ++i) {
mini = i;
for (int j = i + 1; j < array.length; ++j) {
if (array[j].compareTo(array[mini]) < 0) {
mini = j;
}
}
if (i != mini) {
temp = array[i];
array[i] = array[mini];
array[mini] = temp;
}
}
}
}
Result
2/4 + 2/6 = 4/10
Exception in thread "main" java.lang.StackOverflowError
2/4 - 2/6 = 0/-2
at com.xetrasu.Rational.doubleValue(Rational.java:64)
2/4 * 2/6 = 4/24
at com.xetrasu.Rational.doubleValue(Rational.java:64)
2/4 / 2/6 = 12/8
at com.xetrasu.Rational.doubleValue(Rational.java:64)
at com.xetrasu.Rational.doubleValue(Rational.java:64)
at com.xetrasu.Rational.doubleValue(Rational.java:64)
at com.xetrasu.Rational.doubleValue(Rational.java:64)
at com.xetrasu.Rational.doubleValue(Rational.java:64)
Here is the source code of StackOverflowError in OpenJDK 7.

Number pyramid,beginner recursion tracking difficulty?

I am a beginner in JAVA, and I am having some difficulties tracking recursion and understaning it fully and so here I have the code for a program that if we write 3, it will output:
1
12
123
12
1
Or if we write 5, it will output
1
12
123
1234
12345
1234
123
12
1
public class Aufgabe3 {
private static void printSequenz(int n) {
if(n<1) {
return;
}
printLoToHi(n-1);
printMany(n);
printHiToLo(n-1);
}
private static void printHiToLo(int n){
if(n<1){
return;
}
printMany(n);
printHiToLo(n-1);
}
private static void printLoToHi(int n){
if(n<1){
return;
}
printLoToHi(n-1);
printMany(n);
}
private static void printMany(int n){
for(int i=1;i<=n;i++){
System.out.print(i);
}
System.out.println();
}
public static void main(String[] args) {
printSequenz(5);
}
}
Now here is what I don't understand. For example at the method printHiToLo it calls the method printMany(n), and then it calls itself for n-1, and this repeats until n is greater than 0. But I don't understand how the method printLoToHi works? How does it ever reach the printMany method? If it just calls itself until n is greater than 0. This is really confusing to me... Thanks to anyone that helps me out :)
private static void printLoToHi(int n){
if(n<1){ // This is the base case that terminates the recursion.
return; // You'll always have one - sometimes more.
}
printLoToHi(n-1); // This is where the recursion takes place.
printMany(n); // But when n < 1 it returns to here and continues on.
}
So you see it does indeed get called; only after the base case (n < 1) is reached.
An easy example would be if you called it with printLoToHi(1)...
It will pass the if condition.
It calls itself with n - 1 (0) as an argument.
This time it fails the condition and returns.
n == 1 in our original method.
printMany(1) is called.
Look, your functions are executed line by line. So in printLoToHi recursive call is executed and then printMany is called.
For example how works printLoToHi(3):
It checks if 3 less than 1. Then calls printLoToHi(2).
It checks if 2 is less than 1. Then calls printLoToHi(1).
It checks if 1 is less than 1. Then calls printLoToHi(0).
It checks if 0 is less than 1. It is, so it returns.
Then printMany(1) is called.
Then printMany(2) is called.
Then printMany(3) is called.
You can consider a recursive call as a single function which does something and don't think how it works. You can assume it works and write other part of function. If that part is correct - the recursion is correct.

Categories

Resources