3
public class Demo
{
    static int i=0;
    public static void main(String args[])
    {
        System.out.println("Hello"+(i++));
        main(args);
    }
}

In this program I am calling main with instance variable.

It runs properly upto some point but after some Hello prints it gives StackOverFlow Exception.

So i put int to find how many times it gets printed.

I run this program it gives Exception after i=4158.

But I run it several times it gives Exception at different value of i like 4155,4124,4154 etc.

As I know here StackOverFlow is generated because of bad or Unconditional recursive call.

I tried to figure out it but don't know what's exactly happening.

I want to know why after 4158 (or other values) ?

Is it dependent on my System or is it dependent on My Program?

akash
  • 22,664
  • 11
  • 59
  • 87
  • 1
    No. Please. Don't do this. You don't have nearly enough stack to do this. – Makoto Mar 25 '14 at 03:36
  • Are you asking why the number is different each time? Or why it happens at all? – Dawood ibn Kareem Mar 25 '14 at 03:38
  • @Mokoto Okay I won't :) but I just want to know what exact mechanism behind this. – akash Mar 25 '14 at 03:42
  • 2
    OK, I don't know why the number is different each time. As to why it happens, you could do some research into what the stack is, and how it fills up. Maybe start with http://en.wikipedia.org/wiki/Call_stack – Dawood ibn Kareem Mar 25 '14 at 03:46
  • 1
    possible duplicate of [Why does this method print 4?](http://stackoverflow.com/questions/17828584/why-does-this-method-print-4) – Jatin Mar 25 '14 at 03:55
  • Also related: [Stack overflows from deep recursion in Java?](http://stackoverflow.com/questions/860550/stack-overflows-from-deep-recursion-in-java/861385#861385). –  Mar 25 '14 at 04:01

4 Answers4

3

Stack overflows are a general programming error condition that occurs because you've reached the limit of how many recursive calls you can make without returning. This doesn't affect just Java.

Each time that you call a function, a "stack frame" is created, which contains the execution context for the function, such as its local variables. Each stack frame uses up a certain amount of memory, however. A stack overflow occurs when you've either run out of the available memory allocated for function calls, or you've reached some system/environment imposed limit (like your runtime imposing a limit of 10 megabytes, even though you have a gigabyte of memory available).

In order to avoid this infinite recursion condition, you need to have an end-case/condition in which your function determines that it should end the recursion. Here's an example where the end condition is that the recursion depth reaches a maximum of 10, at which point the function stops calling itself and finally returns:

public class Demo
{
    String args[] = new String[10];
    static int i = 0;

    public static void main(String args[])
    {
        if (i >= 10) {
            return;
        }

        System.out.println("Hello" + i++);
        main(args);
    }
}

As for why the value of i keeps changing in your example above, i basically represents how far down the recursion you've gone before you run out of available memory. I'm don't know enough about the details about the Java Virtual Machine and Runtime Environment to be sure, but I'd guess that the value is slightly different each time because the amount of available memory you have is slightly different each time you run the program, due to things like memory garbage collection and stuff like that.

3

First, you're shadowing your args variable. The args defined in your field isn't going to be regarded as the same args you're attempting to recursively call in main.

Second, the recursion eventually runs out, but that's dependent on how much memory you have allocated for the application, and what else is in memory at the time. If you gave it something like 2GB (or more) of space to work with, the recursion would still run out - but likely at a higher value.

As a for-instance, this is what I get when I run with -Xmx6G:

10791
10796
10789

The number is likely different due to what else my OS is running.

Now, for the reason it runs out: your calls are placed on a stack, which is not a finite place in memory; it can (and sometimes does) run out.

Every time you call a function in Java, it goes onto the stack.

First time through:
 > main(0)

main() is always called, so it's always on the bottom of the stack.

If we were to call main() again, then another call of it gets placed on the stack:

Second time through:
 > main(1)
 > main(0)

For most simple applications, only a handful of calls (under 100) are ever put onto the call stack, and their lifecycle is short enough that they don't last on the call stack very long.

However, your application is different, since it's lacking something known as the base case. This is what you use to decide to stop recursing.

Take, for example, the famous factorial function, which states:

      { 1          if n = 0
n! = <
      { n * (n-1)! if n > 0

We have our base case: If n = 0, then we don't continue to recurse any further. Otherwise, we just keep on goin'.

Here's what that looks like in code:

public long factorial(int n) {
    return n == 0 ? 1L : n * factorial(n-1);
}

Once I've reached my base case, then I stop adding calls to the stack - I actually begin resolving them.

Here's a sample of what factorial(4) looks like:

> factorial(4)
  > factorial(3)
    > factorial(2)
      > factorial(1)
        > factorial(0)
        > 1
      > 1 * 1
    > 1 * 1 * 2
  > 1 * 1 * 2 * 3
> 1 * 1 * 2 * 3 * 4

So, this is all to say: if you're going to do a recursive function, make sure that the recursion can end. Otherwise, you'll be running into this issue all the time.

Makoto
  • 104,088
  • 27
  • 192
  • 230
1

It depends on the stack size -Xss not on Xmx.

I've tested your example with values -Xss128k -Xss256k -Xss512k on my 64 bit jvm.

I got 969, 2467, 5436.

So we can see that adding 128k to stack gives ~ 1500 new calls and adding 256k gives ~ 3000 calls. It means one call takes about 80 bytes of stack memory. So 8 of them is a reference to arg, and the others look like some service information to control the flow (try catch) or something else.

Damask
  • 1,754
  • 1
  • 13
  • 24
0

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!!!).

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 for ever. 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 than when calling the function you have at least modified one of the arguments, otherwise there'll be no visible change for the recusivly called function and the terminating condition is useless.

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).

Lavekush Agrawal
  • 6,040
  • 7
  • 52
  • 85