如何增加Java堆栈的大小?

如何增加Java堆栈的大小?,java,stack,stack-overflow,Java,Stack,Stack Overflow,我问这个问题是为了了解如何在JVM中增加运行时调用堆栈的大小。我得到了一个答案,我也得到了许多有用的答案和注释,这些答案和注释与Java如何处理需要大型运行时堆栈的情况有关。我把我的问题扩展到了回答的摘要 最初,我想增加JVM堆栈的大小,以便像这样的程序在运行时不使用StackOverflowerError public class TT { public static long fact(int n) { return n < 2 ? 1 : n * fact(n - 1);

我问这个问题是为了了解如何在JVM中增加运行时调用堆栈的大小。我得到了一个答案,我也得到了许多有用的答案和注释,这些答案和注释与Java如何处理需要大型运行时堆栈的情况有关。我把我的问题扩展到了回答的摘要

最初,我想增加JVM堆栈的大小,以便像这样的程序在运行时不使用
StackOverflowerError

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));
  }
}
其中一个答案还指出,
-X..
标志依赖于实现。我在用

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)
也可以只为一个线程指定一个大堆栈(请参见其中一个答案)。建议在
java-Xss…
上使用此选项,以避免为不需要它的线程浪费内存

我很好奇上面的程序到底需要多大的堆栈,所以我运行了它


  • -Xss4m对于
    fact(1Hmm)来说已经足够了。它对我来说非常有效,并且堆栈的大小远小于999MB:

    > java -Xss4m Test
    0
    

    (Windows JDK 7、build 17.0-b05 client VM和Linux JDK 6-与您发布的版本信息相同)

    如果您想使用线程堆栈大小,您需要查看热点JVM上的-Xss选项。在非热点VM上可能有所不同,因为JVM的-X参数是特定于分发的,IIRC

    在Hotspot上,如果您想制作16兆的尺寸,这看起来像
    java-Xss16M

    如果您想查看可以传入的所有特定于发行版的JVM参数,请键入
    java-X-help
    。我不确定这是否适用于其他JVM,但它会打印所有特定于热点的参数


    值得一提的是,我建议您在Java中限制递归方法的使用。它在优化递归方法方面不是太好,因为JVM不支持尾部递归(请参阅)。请尝试重构上面的阶乘代码,使用while循环而不是递归方法调用。

    我假设您计算了“1024的深度”通过堆栈跟踪中的重复行

    显然,Throwable中的堆栈跟踪数组长度似乎限制为1024。 请尝试以下程序:

    public class Test {
    
        public static void main(String[] args) {
    
            try {
                System.out.println(fact(1 << 15));
            }
            catch (StackOverflowError e) {
                System.err.println("true recursion level was " + level);
                System.err.println("reported recursion level was " +
                                   e.getStackTrace().length);
            }
        }
    
        private static int level = 0;
        public static long fact(int n) {
            level++;
            return n < 2 ? n : n * fact(n - 1);
        }
    }
    
    公共类测试{
    公共静态void main(字符串[]args){
    试一试{
    
    System.out.println(事实(1奇怪!您是说要生成1的递归控制进程内堆栈大小的唯一方法是启动一个新的
    线程
    。但是您也可以通过使用
    -Xss
    参数创建一个自调用子Java进程来控制

    public class TT {
        private static int level = 0;
    
        public static long fact(int n) {
            level++;
            return n < 2 ? n : n * fact(n - 1);
        }
    
        public static void main(String[] args) throws InterruptedException {
            Thread t = new Thread(null, null, "TT", 1000000) {
                @Override
                public void run() {
                    try {
                        level = 0;
                        System.out.println(fact(1 << 15));
                    } catch (StackOverflowError e) {
                        System.err.println("true recursion level was " + level);
                        System.err.println("reported recursion level was "
                                + e.getStackTrace().length);
                    }
                }
    
            };
            t.start();
            t.join();
            try {
                level = 0;
                System.out.println(fact(1 << 15));
            } catch (StackOverflowError e) {
                System.err.println("true recursion level was " + level);
                System.err.println("reported recursion level was "
                        + e.getStackTrace().length);
            }
        }
    
    }
    
    公共类TT{
    私有静态int级别=0;
    公共静态长事实(int n){
    级别++;
    返回n<2?n:n*事实(n-1);
    }
    公共静态void main(字符串[]args)引发InterruptedException{
    线程t=新线程(null,null,“TT”,1000000){
    @凌驾
    公开募捐{
    试一试{
    级别=0;
    
    事实上,很难给出一个合理的解决方案,因为你渴望避免所有合理的方法。重构一行代码是一个可行的解决方案

    注意:使用-Xss设置每个线程的堆栈大小,这是一个非常糟糕的主意

    另一种方法是字节码操作,以如下方式更改代码:

    public static long fact(int n) { 
        return n < 2 ? n : n > 127 ? 0 : n * fact(n - 1); 
    }
    
    公共静态长事实(int n){
    返回n<2?n:n>127?0:n*事实(n-1);
    }
    

    假设n>127的每个答案都是0。这样可以避免更改源代码。

    其他海报已经指出了如何增加内存,并且您可以记忆呼叫。我建议,对于许多应用程序,您可以使用斯特林公式来近似大n!非常快,几乎没有内存占用

    以这篇文章为例,它对函数和代码进行了一些分析:

    我做了,这就像问题一样,但有50000面额(硬币)。我是,我不在乎。我只知道-xss选项没有效果——我总是在1024个堆栈帧后失败(可能是scala在交付到java或printStackTrace限制方面做得不好。我不知道).无论如何,这是一个坏选项。您不希望应用程序中的所有线程都是异常的。但是,我用新线程(堆栈大小)做了一些实验。这确实有效

      def measureStackDepth(ss: Long): Long = {
        var depth: Long = 0
          val thread: Thread = new Thread(null, new Runnable() {
            override def run() {
              try {
              def sum(n: Long): Long = {depth += 1; if (n== 0) 0 else sum(n-1) + 1}
              println("fact = " + sum(ss * 10))
              } catch {
                case e: StackOverflowError => // eat the exception, that is expected
              }
            }
          }, "deep stack for money exchange", ss)
          thread.start()
          thread.join()
        depth
      }                                               //> measureStackDepth: (ss: Long)Long
    
    
      for (ss <- (0 to 10)) println("ss = 10^" +  ss + " allows stack of size " -> measureStackDepth((scala.math.pow (10, ss)).toLong) )
                                                      //> fact = 10
                                                      //| (ss = 10^0 allows stack of size ,11)
                                                      //| fact = 100
                                                      //| (ss = 10^1 allows stack of size ,101)
                                                      //| fact = 1000
                                                      //| (ss = 10^2 allows stack of size ,1001)
                                                      //| fact = 10000
                                                      //| (ss = 10^3 allows stack of size ,10001)
                                                      //| (ss = 10^4 allows stack of size ,1336)
                                                      //| (ss = 10^5 allows stack of size ,5456)
                                                      //| (ss = 10^6 allows stack of size ,62736)
                                                      //| (ss = 10^7 allows stack of size ,623876)
                                                      //| (ss = 10^8 allows stack of size ,6247732)
                                                      //| (ss = 10^9 allows stack of size ,62498160)
    
    def measureStackDepth(ss:Long):Long={
    变量深度:Long=0
    val thread:thread=new thread(null,new Runnable(){
    覆盖def运行(){
    试一试{
    def sum(n:Long):Long={depth+=1;if(n==0)0 else sum(n-1)+1}
    println(“事实=”+总和(ss*10))
    }抓住{
    案例e:StackOverflowerError=>//吃掉预期的异常
    }
    }
    },“货币兑换的深层堆栈”,ss)
    thread.start()
    thread.join()
    深度
    }//>测量堆叠深度:(ss:长)长
    对于(ss measureStackDepth((scala.math.pow(10,ss)).toLong))
    //>事实=10
    //|(ss=10^0允许堆栈大小为11)
    //|事实=100
    //|(ss=10^1允许堆栈大小为101)
    //|事实=1000
    //|(ss=10^2允许大小为1001的堆栈)
    //|事实=10000
    //|(ss=10^3允许堆叠大小,10001)
    //|(ss=10^4允许堆叠大小,1336)
    //|(ss=10^5允许堆栈大小,5456)
    //|(ss=10^6允许堆叠大小,62736)
    //|(s)
    
    public static long fact(int n) { 
        return n < 2 ? n : n > 127 ? 0 : n * fact(n - 1); 
    }
    
      def measureStackDepth(ss: Long): Long = {
        var depth: Long = 0
          val thread: Thread = new Thread(null, new Runnable() {
            override def run() {
              try {
              def sum(n: Long): Long = {depth += 1; if (n== 0) 0 else sum(n-1) + 1}
              println("fact = " + sum(ss * 10))
              } catch {
                case e: StackOverflowError => // eat the exception, that is expected
              }
            }
          }, "deep stack for money exchange", ss)
          thread.start()
          thread.join()
        depth
      }                                               //> measureStackDepth: (ss: Long)Long
    
    
      for (ss <- (0 to 10)) println("ss = 10^" +  ss + " allows stack of size " -> measureStackDepth((scala.math.pow (10, ss)).toLong) )
                                                      //> fact = 10
                                                      //| (ss = 10^0 allows stack of size ,11)
                                                      //| fact = 100
                                                      //| (ss = 10^1 allows stack of size ,101)
                                                      //| fact = 1000
                                                      //| (ss = 10^2 allows stack of size ,1001)
                                                      //| fact = 10000
                                                      //| (ss = 10^3 allows stack of size ,10001)
                                                      //| (ss = 10^4 allows stack of size ,1336)
                                                      //| (ss = 10^5 allows stack of size ,5456)
                                                      //| (ss = 10^6 allows stack of size ,62736)
                                                      //| (ss = 10^7 allows stack of size ,623876)
                                                      //| (ss = 10^8 allows stack of size ,6247732)
                                                      //| (ss = 10^9 allows stack of size ,62498160)
    
    --driver-java-options -Xss512m