What actually causes a Stack Overflow error?

JavaJvmStack Overflow

Java Problem Overview


I've looked everywhere and can't find a solid answer. According to the documentation, Java throws a [java.lang.StackOverflowError][1] error under the following circumstance:

> Thrown when a stack overflow occurs because an application recurses too deeply.

But this raises two questions:

  • Aren't there other ways for a stack overflow to occur, not only through recursion?
  • Does the StackOverflowError happen before the JVM actually overflows the stack or after?

To elaborate on the second question:

When Java throws the StackOverflowError, can you safely assume that the stack did not write into the heap? If you shrink the size of the stack or heap in a try/catch on a function that throws a stack overflow, can you continue working? Is this documented anywhere?

Answers I am not looking for:

  • A StackOverflow happens because of bad recursion.
  • A StackOverflow happens when the heap meets the stack.

[1]: http://docs.oracle.com/javase/7/docs/api/java/lang/StackOverflowError.html "java.lang.StackOverflowError"

Java Solutions


Solution 1 - Java

It seems you're thinking that a stackoverflow error is like a buffer overflow exception in native programs, when there is a risk of writing into memory that had not been allocated for the buffer, and thus to corrupt some other memory locations. It's not the case at all.

JVM has a given memory allocated for each stack of each thread, and if an attempt to call a method happens to fill this memory, JVM throws an error. Just like it would do if you were trying to write at index N of an array of length N. No memory corruption can happen. The stack can not write into the heap.

A StackOverflowError is to the stack what an OutOfMemoryError is to the heap: it simply signals that there is no more memory available.

Description from Virtual Machine Errors (§6.3)

> StackOverflowError: The Java Virtual Machine implementation has run out of stack space for a thread, typically because the thread is doing an unbounded number of recursive invocations as a result of a fault in the executing program.

Solution 2 - Java

> Aren't there other ways for a stack overflow to occur, not only through recursion?

Sure. Just keep calling methods, without ever returning. You'll need a lot of methods, though, unless you allow recursion. Actually, it doesn't make a difference: a stack frame is a stack frame, whether it is one of a recursive method or not is the same.

The answer to your second question is: The stackoverflow is detected when the JVM tries to allocate the stack frame for the next call, and finds it is not possible. So, nothing will be overwritten.

Solution 3 - Java

> Aren't there other ways for a stack overflow to occur, not only > through recursion?

Challenge accepted :) StackOverflowError without recursion (challenge failed, see comments):

public class Test
{
	final static int CALLS = 710;

	public static void main(String[] args)
	{
		final Functor[] functors = new Functor[CALLS];
		for (int i = 0; i < CALLS; i++)
		{
			final int finalInt = i;
			functors[i] = new Functor()
			{
				@Override
				public void fun()
				{
					System.out.print(finalInt + " ");
					if (finalInt != CALLS - 1)
					{
						functors[finalInt + 1].fun();
					}
				}
			};
		}
        // Let's get ready to ruuuuuuumble!
		functors[0].fun(); // Sorry, couldn't resist to not comment in such moment. 
	}

	interface Functor
	{
		void fun();
	}
}

Compile with standard javac Test.java and run with java -Xss104k Test 2> out. After that, more out will tell you:

Exception in thread "main" java.lang.StackOverflowError

Second try.

Now the idea is even simpler. Primitives in Java can be stored on the stack. So, let's declare a lot of doubles, like double a1,a2,a3.... This script can write, compile and run the code for us:

#!/bin/sh

VARIABLES=4000
NAME=Test
FILE=$NAME.java
SOURCE="public class $NAME{public static void main(String[] args){double "
for i in $(seq 1 $VARIABLES);
do
	SOURCE=$SOURCE"a$i,"
done
SOURCE=$SOURCE"b=0;System.out.println(b);}}"
echo $SOURCE > $FILE
javac $FILE
java -Xss104k $NAME

And... I got something unexpected:

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x00007f4822f9d501, pid=4988, tid=139947823249152
#
# JRE version: 6.0_27-b27
# Java VM: OpenJDK 64-Bit Server VM (20.0-b12 mixed mode linux-amd64 compressed oops)
# Derivative: IcedTea6 1.12.6
# Distribution: Ubuntu 10.04.1 LTS, package 6b27-1.12.6-1ubuntu0.10.04.2
# Problematic frame:
# V  [libjvm.so+0x4ce501]  JavaThread::last_frame()+0xa1
#
# An error report file with more information is saved as:
# /home/adam/Desktop/test/hs_err_pid4988.log
#
# If you would like to submit a bug report, please include
# instructions how to reproduce the bug and visit:
#   https://bugs.launchpad.net/ubuntu/+source/openjdk-6/
#
Aborted

It's 100% repetitive. This is related to your second question: > Does the StackOverflowError happen before the JVM actually overflows > the stack or after?

So, in case of OpenJDK 20.0-b12 we can see that JVM firstly exploded. But it seems like a bug, maybe someone can confirm that in comments please, because I'm not sure. Should I report this? Maybe it's already fixed in some newer version... According to JVM specification link (given by JB Nizet in a comment) JVM should throw a StackOverflowError, not die:

> If the computation in a thread requires a larger Java Virtual Machine > stack than is permitted, the Java Virtual Machine throws a > StackOverflowError.


Third try.

public class Test {
    Test test = new Test();

    public static void main(String[] args) {
        new Test();
    }
}

We want to create new Test object. So, its (implicit) constructor will be called. But, just before that, all the members of Test are initialized. So, Test test = new Test() is executed first...

We want to create new Test object...

Update: Bad luck, this is recursion, I asked question about that here.

Solution 4 - Java

There is no "StackOverFlowException". What you mean is "StackOverFlowError".

Yes you can continue working if you catch it because the stack is cleared when you do that but that would be a bad and ugly option.

When exactly the error is thrown ? - When you call a method and the JVM verifies if there is enough memory to do it. Of course, the error is thrown if it's not possible.

  • No, that is the only way you can get that error: getting your stack full. But not only through recursion, also calling methods that infinitely call other methods. It's a very specific error so no.
  • It is thrown before the stack is full, exactly when you verify it. Where would you put the data if there is no space available ? Overriding others ? Naah.

Solution 5 - Java

There are two main places that things can be stored in Java. The first is the Heap, that's used for dynamically allocated objects. new.

In addition each running thread gets its own stack, and it gets an amount of memory allocated to that stack.

When you call a method then data is pushed into the stack to record the method call, the parameters being passed in, and any local variables being allocated. A method with five local variables and three parameters will use more stack space than a void doStuff() method with no local variables will.

The main advantages of the stack are that there is no memory fragmentation, everything for one method call is allocated on the top of the stack, and that returning from methods is easy. To return from a method you just unwind the stack back to the previous method, set any value needed for the return value and you are done.

Because the stack is a fixed size per thread, (note that the Java Spec does not require a fixed size, but most JVM implementations at the time of writing use a fixed size) and because space on the stack is needed whenever you make a method call hopefully it should now be clear why it can run out and what can cause it to run out. There isn't a fixed number of method calls, there isn't anything specific about recursion, you get the exception which you try to call a method and there isn't enough memory.

Of course the size of stacks is set high enough that it is highly unlikely to happen in regular code. In recursive code though it can be quite easy to recurse to huge depths, and at that point you start running into this error.

Solution 6 - Java

The most common cause of StackOverFlowError is excessively deep or infinite recursion.

For instance:

public int yourMethod(){
       yourMethod();//infinite recursion
}

In Java:

There are two areas in memory the heap and stack. The stack memory is used to store local variables and function call, while heap memory is used to store objects in Java.

If there is no memory left in stack for storing function call or local variable, JVM will throw java.lang.StackOverFlowError

while if there is no more heap space for creating object, JVM will throw java.lang.OutOfMemoryError

Solution 7 - Java

StackOverflowError occurs due to an application recurses too deeply (This is not an answer you are expecting).

Now other things to happen to StackOverflowError is keep calling methods from methods till you get StackOverflowError, but nobody can program to get StackOverflowError and even if those programmer are doing so then they are not following coding standards for cyclomatic complixity that every programmer has to understand while programming. Such reason for 'StackOverflowError' will require much time to rectify it.

But unknowingly coding one line or two line which causes StackOverflowError is understandable and JVM throws that and we can rectify it instantly. Here is my answer with picture for some other question.

Solution 8 - Java

A StackOverflow happens when a function call is made and the stack is full.

Just like an ArrayOutOfBoundException. It cannot corrupt anything, in fact it is very possible to catch it and recover from it.

It usually happens as the result of an uncontrolled recursion, but it can also be caused by simply have a very deep stack of functions call.

Solution 9 - Java

In c# you can achieve stack overflow in a different manner, by wrongly defining object properties. For example :

private double hours;

public double Hours
        {
            get { return Hours; }
            set { Hours = value; }
        }

As you can see this will forever keep on returning Hours with an uppercase H , which in itself will return Hours and so and so on.

A stack overflow will often occur also because of running out of memory or when using managed languages because your language manager (CLR, JRE) will detect that your code got stuck in an infinite loop.

Solution 10 - Java

> But this raises two questions: > > 1. Aren't there other ways for a stack overflow to occur, not only through recursion? > 2. Does the StackOverflowError happen before the JVM actually overflows the stack or after?

  1. It can also occur when we are Allocating size greater than stack's limit (for eg. int x[10000000];).

  2. Answer to second is

Each thread has its own stack that holds a frame for each method executing on that thread. So the currently executing method is at the top of the stack. A new frame is created and added (pushed) to the top of stack for every method invocation. The frame is removed (popped) when the method returns normally or if an uncaught exception is thrown during the method invocation. The stack is not directly manipulated, except to push and pop frame objects, and therefore the frame objects may be allocated in the Heap and the memory does not need to be contiguous.

So by considering stack in a Thread we can conclude.

A stack can be a dynamic or fixed size. If a thread requires a larger stack than allowed a StackOverflowError is thrown. If a thread requires a new frame and there isn’t enough memory to allocate it then an OutOfMemoryError is thrown.

you can get description for JVM here

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionretrohackerView Question on Stackoverflow
Solution 1 - JavaJB NizetView Answer on Stackoverflow
Solution 2 - JavaIngoView Answer on Stackoverflow
Solution 3 - JavaAdam StelmaszczykView Answer on Stackoverflow
Solution 4 - JavaGabrielBBView Answer on Stackoverflow
Solution 5 - JavaTim BView Answer on Stackoverflow
Solution 6 - JavaLazy CoderView Answer on Stackoverflow
Solution 7 - JavaAmitGView Answer on Stackoverflow
Solution 8 - Javanjzk2View Answer on Stackoverflow
Solution 9 - JavaBryan Arbelo - MaG3SticanView Answer on Stackoverflow
Solution 10 - JavaeatSleepCodeView Answer on Stackoverflow