Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/heroku/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java中深度递归的堆栈溢出?_Java_Functional Programming_Stack_Overflow - Fatal编程技术网

Java中深度递归的堆栈溢出?

Java中深度递归的堆栈溢出?,java,functional-programming,stack,overflow,Java,Functional Programming,Stack,Overflow,在对函数式语言有了一些经验之后,我开始在Java中更多地使用递归——但该语言似乎有一个相对较浅的调用堆栈,大约1000个 有没有办法使调用堆栈变大?比如,我可以像在Erlang中那样生成数百万次调用深度的函数吗 当我处理Euler问题时,我越来越注意到这一点 谢谢。我想您可以使用这些参数 -ss Stacksize以增加本机 堆栈大小或 -oss Stacksize增加了Java 堆栈大小 默认本机堆栈大小为128k, 最小值为1000字节。 默认java堆栈大小为400k, 最小值为1000字

在对函数式语言有了一些经验之后,我开始在Java中更多地使用递归——但该语言似乎有一个相对较浅的调用堆栈,大约1000个

有没有办法使调用堆栈变大?比如,我可以像在Erlang中那样生成数百万次调用深度的函数吗

当我处理Euler问题时,我越来越注意到这一点


谢谢。

我想您可以使用这些参数

-ss Stacksize以增加本机 堆栈大小或

-oss Stacksize增加了Java 堆栈大小

默认本机堆栈大小为128k, 最小值为1000字节。 默认java堆栈大小为400k, 最小值为1000字节

编辑:


在阅读了第一条评论(Chuck’s)以及重新阅读问题和其他答案后,我想澄清一下,我将问题解释为“增加堆栈大小”。我不想说你可以有无限的堆栈,比如在函数式编程中(我只是触及了它的表面)。大多数函数式语言都支持尾部递归。但是,大多数Java编译器都不支持这一点。相反,它会进行另一个函数调用。这意味着您可以进行的递归调用的数量始终有一个上限(因为您最终将耗尽堆栈空间)


对于尾部递归,您可以重用正在递归的函数的堆栈框架,因此堆栈上没有相同的约束。

是否使用尾部递归取决于JVM-我不知道它们是否使用尾部递归,但您不应该依赖它。特别是,更改堆栈大小很少是正确的做法,除非您对实际使用的递归级别有严格限制,并且您确切地知道每个级别将占用多少堆栈空间。非常脆弱

基本上,您不应该在不是为其构建的语言中使用无界递归。恐怕您将不得不使用迭代。是的,有时会有轻微的疼痛:(

现在,虽然您可能可以找到一种方法来增加java中的默认堆栈,但让我添加我的2美分,因为您确实需要找到另一种方法来做您想做的事情,而不是依赖于增加的堆栈


由于java规范没有强制要求JVM实现尾部递归优化技术,因此解决此问题的唯一方法是减少堆栈压力,或者减少需要跟踪的局部变量/参数的数量,或者理想情况下,通过显著降低递归级别,或者完全不使用递归重写。

您可以在命令行上设置:


java-Xss8M类

Clojure运行在java虚拟机上,非常希望实现尾部调用优化,但由于JVM字节码中的限制(我不知道细节),它不能实现。因此,它只能通过一个特殊的“重复”来帮助自己表单,它实现了正确的尾部递归所期望的一些基本特性


无论如何,这意味着JVM目前无法支持尾部调用优化。我强烈建议不要在JVM上使用递归作为一般循环结构。我个人的观点是Java不是一种足够高级的语言。

增加堆栈大小只会起到暂时的束缚作用。正如其他人所指出的,w您真正想要的是尾部调用消除,Java由于各种原因没有这样做。但是,如果您愿意,您可以作弊

手里拿着红色药丸?好的,请这边走

有一些方法可以交换堆栈,例如,在函数内不调用递归调用,返回一个强的>惰性数据结构<强>,这样调用时就可以调用该调用。然后,可以用java的结构解压缩“栈”。

map :: (a -> b) -> [a] -> [b]
map _ [] = []
map f (x:xs) = (f x) : map f xs
请注意,此函数从不计算列表的尾部。因此,该函数实际上不需要进行递归调用。在Haskell中,它实际上返回尾部的thunk,如果需要,将调用该尾部。我们可以在Java中执行相同的操作(这使用来自的类):

这是另一个例子,因为您在谈论Project Euler。该程序使用相互递归的函数,即使是数百万次调用,也不会破坏堆栈:

import fj.*; import fj.data.Natural;
import static fj.data.Enumerator.naturalEnumerator;
import static fj.data.Natural.*; import static fj.pre.Ord.naturalOrd;
import fj.data.Stream; import fj.data.vector.V2;
import static fj.data.Stream.*; import static fj.pre.Show.*;

public class Primes
  {public static Stream<Natural> primes()
    {return cons(natural(2).some(), new P1<Stream<Natural>>()
       {public Stream<Natural> _1()
         {return forever(naturalEnumerator, natural(3).some(), 2)
                 .filter(new F<Natural, Boolean>()
                   {public Boolean f(final Natural n)
                      {return primeFactors(n).length() == 1;}});}});}

   public static Stream<Natural> primeFactors(final Natural n)
     {return factor(n, natural(2).some(), primes().tail());}

   public static Stream<Natural> factor(final Natural n, final Natural p,
                                        final P1<Stream<Natural>> ps)
     {for (Stream<Natural> ns = cons(p, ps); true; ns = ns.tail()._1())
          {final Natural h = ns.head();
           final P1<Stream<Natural>> t = ns.tail();
           if (naturalOrd.isGreaterThan(h.multiply(h), n))
              return single(n);
           else {final V2<Natural> dm = n.divmod(h);
                 if (naturalOrd.eq(dm._2(), ZERO))
                    return cons(h, new P1<Stream<Natural>>()
                      {public Stream<Natural> _1()
                        {return factor(dm._1(), h, t);}});}}}

   public static void main(final String[] a)
     {streamShow(naturalShow).println(primes().takeWhile
       (naturalOrd.isLessThan(natural(Long.valueOf(a[0])).some())));}}
strategys
由线程池支持,而
promise
函数将thunk传递给线程池,返回一个
promise
,非常类似于
java.util.concurrent.Future
,只是更好。重点是上面的方法在O(1)中将一个右递归数据结构向右折叠堆栈,通常需要消除尾部调用。因此,我们有效地实现了TCE,以换取一些复杂性。您可以按如下方式调用此函数:

Strategy<Unit> s = Strategy.simpleThreadStrategy();
int x = foldRight(s, Integers.add, List.nil(), range(1, 10000)).claim();
System.out.println(x); // 49995000
这与使用多个线程的原理相同,不同的是,我们不是在自己的线程中调用每个步骤,而是在堆上构造每个步骤,非常类似于使用
,然后使用
蹦床在单个循环中运行所有步骤。运行

公共静态承诺foldRight(最终策略s,
public static <A, B> Promise<B> foldRight(final Strategy<Unit> s,
                                          final F<A, F<B, B>> f,
                                          final B b,
                                          final List<A> as)
{
    return as.isEmpty() ? promise(s, P.p(b))
    : liftM2(f).f(promise(s, P.p(as.head())))
      .f(join(s, new F<List<A>, P1<Promise<B>>>()
        {
             public Promise<B> f(List<A> l)
             {
                 return foldRight(s, f, b, l);
             }
         }.f(as.tail())));
}
最后的F, 最后的B, 最终名单(见附件) { 以.isEmpty()的形式返回?承诺(s,P.P(b)) :liftM2(f).f(promise(s,P.P(as.head())) .f(加入,新的f() { 公共承诺f(列表l) { 返回文件夹(s、f、b、l); } }.f(as.tail()); }
在eclipse中,如果正在使用,请将-xss2m设置为vm参数

-xss2m直接在命令行上

java -xss2m classname

我遇到了同样的问题,结果将递归重写为for
Strategy<Unit> s = Strategy.simpleThreadStrategy();
int x = foldRight(s, Integers.add, List.nil(), range(1, 10000)).claim();
System.out.println(x); // 49995000
public final <B> Trampoline<B> foldRightC(final F2<A, B, B> f, final B b)
  {return Trampoline.suspend(new P1<Trampoline<B>>()
    {public Trampoline<B> _1()
      {return isEmpty()
         ? Trampoline.pure(b)
         : tail().foldRightC(f, b).map(f.f(head()));}});}
public static <A, B> Promise<B> foldRight(final Strategy<Unit> s,
                                          final F<A, F<B, B>> f,
                                          final B b,
                                          final List<A> as)
{
    return as.isEmpty() ? promise(s, P.p(b))
    : liftM2(f).f(promise(s, P.p(as.head())))
      .f(join(s, new F<List<A>, P1<Promise<B>>>()
        {
             public Promise<B> f(List<A> l)
             {
                 return foldRight(s, f, b, l);
             }
         }.f(as.tail())));
}
java -xss2m classname