Wie kann die Größe des Java-Stacks erhöht werden?

Ich habe diese Frage gestellt, um zu erfahren, wie die Größe des Runtime-Aufrufstapels in der JVM erhöht werden kann. Ich habe eine Antwort darauf und viele nützliche Antworten und Kommentare, die sich darauf beziehen, wie Java mit der Situation umgeht, in der ein großer Laufzeitstapel benötigt wird. Ich habe meine Frage um die Zusammenfassung der Antworten erweitert.

Ursprünglich wollte ich die Größe des JVM-Stacks erhöhen, damit Programme wie ohne @ ausgeführt werden könneStackOverflowError.

public class TT {
  public static long fact(int n) {
    return n < 2 ? 1 : n * fact(n - 1);
  }
  public static void main(String[] args) {
    System.out.println(fact(1 << 15));
  }
}

Die entsprechende Konfigurationseinstellung ist dasjava -Xss... Befehlszeilenflag mit einem ausreichend großen Wert. Für das ProgrammTT oben, es funktioniert so mit OpenJDK's JVM:

$ javac TT.java
$ java -Xss4m TT

Eine der Antworten hat auch darauf hingewiesen, dass die-X... Flags sind implementierungsabhängig. Ich habe @ benut

java version "1.6.0_18"
OpenJDK Runtime Environment (IcedTea6 1.8.1) (6b18-1.8.1-0ubuntu1~8.04.3)
OpenJDK 64-Bit Server VM (build 16.0-b13, mixed mode)

Es ist auch möglich, einen großen Stapel nur für einen Thread anzugeben (siehe in einer der Antworten, wie). Dies wird empfohlen überjava -Xss..., um nicht Speicher für Threads zu verschwenden, die ihn nicht benötigen.

Ich war neugierig, wie groß ein Stapel ist, den das Programm oben genau benötigt, also habe ich ihn ausgeführtn ist gestiegen

-Xss4m kann genug sein fürfact(1 << 15) -Xss5m kann genug sein fürfact(1 << 17) -Xss7m kann genug sein fürfact(1 << 18) -Xss9m kann genug sein fürfact(1 << 19) -Xss18m kann genug sein fürfact(1 << 20) -Xss35m kann genug sein fürfact(1 << 21) -Xss68m kann genug sein fürfact(1 << 22) -Xss129m kann genug sein fürfact(1 << 23) -Xss258m kann genug sein fürfact(1 << 24) -Xss515m kann genug sein fürfact(1 << 25)

us den obigen Zahlen geht hervor, dass Java für die obige Funktion ungefähr 16 Bytes pro Stack-Frame verwendet, was angemessen is

Die obige Aufzählung enthältkann genug sein Anstatt vonreich, da die Stack-Anforderung nicht deterministisch ist: Es wird mehrmals mit derselben Quelldatei und demselben @ ausgeführ-Xss... ist manchmal erfolgreich und liefert manchmal einStackOverflowError. Z.B. für 1 << 20,-Xss18m war genug in 7 von 10 Läufen, und-Xss19m war auch nicht immer genug, aber-Xss20m hat gereicht (insgesamt 100 Läufe von 100). Verursacht die Garbage Collection, der JIT-Kick oder etwas anderes dieses nicht deterministische Verhalten?

Die Stapelspur wird bei einem @ gedrucStackOverflowError (und möglicherweise auch in anderen Ausnahmefällen) zeigt nur die neuesten 1024 Elemente des Laufzeitstacks an. Die folgende Antwort zeigt, wie die genaue erreichte Tiefe gezählt wird (die viel größer als 1024 sein kann).

Viele Personen, die geantwortet haben, haben darauf hingewiesen, dass es eine gute und sichere Codierungspraxis ist, alternative, aktive und weniger stapelhungrige Implementierungen desselben Algorithmus in Betracht zu ziehen. Im Allgemeinen ist es möglich, eine Menge von rekursiven Funktionen in iterative Funktionen umzuwandeln (unter Verwendung eines z. B.Stack Objekt, das auf dem Heap statt auf dem Runtime-Stack aufgefüllt wird). Für dieses besonderefact Funktion, es ist ziemlich einfach, es zu konvertieren. Meine iterative Version würde so aussehen:

public class TTIterative {
  public static long fact(int n) {
    if (n < 2) return 1;
    if (n > 65) return 0;  // Enough powers of 2 in the product to make it (long)0.
    long f = 2;
    for (int i = 3; i <= n; ++i) {
      f *= i;
    }
    return f;
  }
  public static void main(String[] args) {
    System.out.println(fact(1 << 15));
  }
}

FYI, wie die obige iterative Lösung zeigt, dasfactie @ -Funktion kann die exakte Fakultät von Zahlen über 65 (tatsächlich sogar über 20) nicht berechnen, da der in Java integrierte Typlong würde überlaufen. Refactoringfact so würde es ein @ zurückgebBigInteger Anstatt vonlong würde auch bei großen Eingaben genaue Ergebnisse liefern.

Antworten auf die Frage(18)

Ihre Antwort auf die Frage