Jaka jest maksymalna głębokość stosu wywołań Java?


100

Jak głęboko muszę wejść do stosu wywołań, zanim otrzymam StackOverflowError? Czy platforma odpowiedzi jest zależna?



Ponieważ jest to dobre pytanie, zaktualizowałem tytuł do czegoś, co moim zdaniem jest wyraźniej związane ze znaczeniem. (Wcześniej myślałem, że możesz odnosić się do głębokości konkretnego stosu, który przechwyciłeś na przykład w czasie wykonywania). Jeśli się nie zgadzasz, możesz to zmienić.
Andrzej Doyle

Odpowiedzi:



31

Testowałem na swoim systemie i nie znalazłem żadnej stałej wartości, czasami przepełnienie stosu występuje po 8900 wywołaniach, czasami tylko po 7700, losowych liczbach.

public class MainClass {

    private static long depth=0L;

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

    private static void deep(){
        System.err.println(++depth);
        deep();
    }

}

15
Czy nie jest tak, że to jest ogon rekurencyjny i nie powinien nigdy się przepełniać? Edycja: przepraszam. W Javie rozbił się na 8027; w Scali doszło do 8594755, zanim się znudziłem.
arya

9
@arya, ważną częścią semantyki JVM jest to, że rekurencja ogona nie jest obsługiwana. Daje to wiele interesujących problemów dla tych, którzy chcą zaimplementować języki z rekurencją ogonową w JVM.
Thorbjørn Ravn Andersen

2
public foo() { try { foo(); } finally { foo(); } }może działać „wirtualnie” w nieskończoność, ale tylko w Javie.
Felype

u mnie StackOverflowErrorwystępuje po 8792
ericdemo07

2
@ ThorbjørnRavnAndersen Optymalizacja rekurencji ogona nie jest obsługiwana. Raczej oczywiście możesz mieć rekurencję ogonową. Po prostu nie optymalizuje go, aby nie powiększał stosu wywołań.
slim

19

Rozmiar stosu można ustawić za pomocą -Xssprzełącznika wiersza poleceń, ale z reguły jest on wystarczająco duży, setki, jeśli nie tysiące połączeń. (Wartość domyślna zależy od platformy, ale na większości platform co najmniej 256 KB).

Jeśli otrzymasz przepełnienie stosu, w 99% przypadków jest to spowodowane błędem w kodzie.


3
+1 za drugi akapit. Należy o tym zawsze pamiętać.
mcveat

6
Używając eclipse, otrzymuję tylko 1024 rekurencyjne wywołania.
Norswap,

2
@Norswap Czy określasz to na podstawie rozmiaru śladu stosu? Wydaje się, że jest to ograniczone do 1024, niezależnie od rzeczywistego rozmiaru stosu.
Brian McCutchon

4

Porównaj te dwa wywołania:
(1) Metoda statyczna:

public static void main(String[] args) {
    int i = 14400; 
    while(true){   
        int myResult = testRecursion(i);
        System.out.println(myResult);
        i++;
    }
}

public static int testRecursion(int number) {
    if (number == 1) {
        return 1;
    } else {
        int result = 1 + testRecursion(number - 1);
        return result;
    }    
}
 //Exception in thread "main" java.lang.StackOverflowError after 62844

(2) Metoda niestatyczna wykorzystująca inną klasę:

public static void main(String[] args) {
    int i = 14400;
    while(true){       
        TestRecursion tr = new TestRecursion ();
        int myResult = tr.testRecursion(i);
        System.out.println(myResult);
        i++;
    }
} 
//Exception in thread "main" java.lang.StackOverflowError after 14002

Klasa testowa rekursji ma public int testRecursion(int number) {jako jedyną metodę.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.