Balu
Balu

Reputation: 126

Is error recovery possible in Java?

Consider the following code which generates StackOverflowError.

public class SimpleProgram {
  static SimpleProgram s = new SimpleProgram();

  public static void main(String[] args) {
      s.f(0);
  }

  void f(int i) {
      System.out.println("f :" + (++i));
      g(i);
  }

  void g(int i) {
      System.out.println("g :" + (++i));
      f(i);
  }
}

It simply prints the number from 1 to n ( '5417' by f() when I executed ). After that it throws StackOverflowError and terminates. Now consider the second program.

public class SimpleProgram{
  static SimplePrograms = new SimpleProgram();

  public static void main(String[] args) {
      s.f(0);
  }

  void f(int i) {
      try {
          System.out.println("f :" + (++i));
          g(i);
      } catch (StackOverflowError e) {
          System.out.println("f :" + (++i));
          g(i);
      }
  }

  void g(int i) {
      try {
          System.out.println("g :" + (++i));
          f(i);
      } catch (StackOverflowError e) {
          System.out.println("g :" + (++i));
          f(i);
      }
  }
}

Now it shows some strange behavior. The program doesn't terminate as expected, but the values displayed are repeated ( say f :4107 g :4108 to f :4120 and again back to f :4107).

My question is, why is this happening? I thought an error like StackOverflowError means the current thread's stack is full and hence there is no recovery. The program has to stop it's execution forcefully i.e doesn't call next function, but didn't happen. Can JVM thread stack increase its size on demand?

Upvotes: 4

Views: 1282

Answers (2)

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726929

What you see has to do with the way your program is constructed more than with the way Java handles errors. Your program creates two points of retry at each of n invocation levels, so the total number of paths through the program grows exponentially.

Let's consider what would happen if only three call levels were sufficient to overflow the stack:

main -> f(0)
f(0) -> g(0)
g(0) -> f(1)
f(1) -> g(1)
g(1) -> f(2)
f(2) -> g(2)
g(2) -> f(3) <<== Stack overflow

What happens next? The stack begins unwinding. Each method has installed a handler for StackOverflowError, so they would be handling the error and calling the same function again:

g(2) handler -> f(3) <<== Stack overflow #2
f(2) handler -> g(2)
g(2) -> f(3)         <<== Stack overflow #3
g(2) handler -> f(3) <<== Stack overflow #4
g(1) handler -> f(2)
f(2) -> g(2)
g(2) -> f(3)         <<== Stack overflow #5
f(1) handler -> g(1)
g(1) -> f(2)
f(2) -> g(2)
g(2) -> f(3)         <<== Stack overflow #6
g(0) handler -> f(1)
f(1) -> g(1)
g(1) -> f(2)
f(2) -> g(2)
g(2) -> f(3)         <<== Stack overflow #7
f(0) handler -> g(0)
g(0) -> f(1)
f(1) -> g(1)
g(1) -> f(2)
f(2) -> g(2)
g(2) -> f(3)         <<== Stack overflow #8

As you can see, this chain unwinds eventually, but it goes up and down many times for only three levels. With thousands of levels, the number would be much higher: the count of errors your get goes up two times for each f or g level on the way to overflow, so it is 2n for n frames. With n in the thousands, you can consider your program infinite.

Upvotes: 2

Eran
Eran

Reputation: 393986

Your exception handlers makes more method calls (to System.out.println() and either f() or g()). These calls may throw a new StackOverflowError, which may be caught a few levels down the call stack, so you'll see the numbers going down and back up infinitely (since as the exception goes down the methods in the call stack, some space is freed in the call stack, so there's room for additional calls to be made).

Here's part of the output I got (to make it clearer, I added "catch" to the println statements inside the catch blocks) :

The first StackOverflowError happens when System.out.println(String) attempts to call println(), which is why no new line is displayed in g :9662catch g :9663. For some reason, after the first StackOverflowError, there is room to about 50 additional calls until we get another StackOverflowError, after which the errors come more periodically.

... no eception till this point...
g :9660
f :9661
g :9662catch g :9663 
f :9664
g :9665
f :9666
g :9667
f :9668
g :9669
f :9670
g :9671
f :9672
g :9673
f :9674
g :9675
f :9676
g :9677
f :9678
g :9679
f :9680
g :9681
f :9682
g :9683
f :9684
g :9685
f :9686
g :9687
f :9688
g :9689
f :9690
g :9691
f :9692
g :9693
f :9694
g :9695
f :9696
g :9697
f :9698
g :9699
f :9700
g :9701
f :9702
g :9703catch g :9704catch f :9703
g :9704catch g :9705catch g :9702
f :9703
g :9704catch g :9705catch f :9704
g :9705catch g :9706catch f :9701
g :9702
f :9703
g :9704catch g :9705catch f :9704
g :9705catch g :9706catch g :9703
f :9704
g :9705catch g :9706catch f :9705
g :9706catch g :9707catch g :9700
f :9701
g :9702
f :9703
g :9704catch g :9705catch f :9704
g :9705catch g :9706catch g :9703
f :9704
g :9705catch g :9706catch f :9705
g :9706catch g :9707catch f :9702
g :9703
f :9704
g :9705catch g :9706catch f :9705
g :9706catch g :9707catch g :9704
f :9705
....

Upvotes: 2

Related Questions