JVM是否阻止尾部调用优化?


Answers:


74

帖子:递归还是迭代?可能有帮助。

简而言之,由于安全模型和始终需要可用的堆栈跟踪,因此在JVM中很难进行尾部调用优化。这些要求在理论上可以得到支持,但是可能需要一个新的字节码(请参阅John Rose的非正式建议)。

Sun bug#4726340中还有更多讨论,评估(从2002年开始)在此结束:

我相信仍然可以做到这一点,但这不是一个小任务。

当前,达芬奇机器项目中正在进行一些工作。尾部调用子项目的状态列为“原始80%”;不太可能将其纳入Java 7,但我认为它在Java 8中有很大的机会。


我不太听从解释。我认为尾部调用优化是由编译器实现的。假设您有一个可以由编译器进行尾调用优化的函数,那么您还可以拥有一个等效的非递归函数,该函数使用循环来实现相同的功能,对吗?如果是这样,编译器不能完成此操作。我无法遵循对JVM的依赖。这与生成本机i386代码的Scheme编译器相比如何?
Gautham Ganapathy,2009年

4
@Gautham:我关于调试的声明是关于使用蹦床作为解决JVM缺少尾部调用的变通方法的。可以并且已经在JVM上实现了尾部调用消除(Arnold Schaighofer在OpenJDK中以及在LLVM中进行了实现),因此毫无疑问是否可以完成。当然,微软的CLR支持消除尾声已达10年之久,而F#的发布证明它可以改变游戏规则。我认为答案是JVM早已停滞。
JD

3
这是一个普遍的误解,而且是经常重复的借口,但这是不正确的。多年以来,人们已经公认,通过堆栈检查(以及提供有用的堆栈跟踪)进行的安全性与适当的尾部调用不兼容。例如,请参阅2004年的这篇论文。citeseerx.ist.psu.edu/ viewdoc/… 投票不足,因为答案不正确。
贾斯汀·谢伊

5
@JustinSheehy:什么不正确?问题是,“ JVM是否阻止了尾部调用优化?” 答案是:“不,但是很难。”
迈克尔·迈尔斯

5
你知道java8中是否包含这个?
nachokk

27

基本的限制仅仅是,JVM不在其字节码中提供尾部调用,因此,没有直接方法可以使基于JVM的语言本身提供尾部调用。有一些变通办法可以达到类似的效果(例如,踩踏),但代价是糟糕的性能以及混淆生成的中间代码,这使调试器无用,从而付出了巨大的代价。

因此,除非Sun在JVM本身中实现尾调用,否则JVM无法支持任何具有生产质量的功能编程语言。他们已经讨论了很多年,但是我怀疑它们是否会实现尾部调用:这将非常困难,因为在实现这种基本功能之前,他们过早地优化了VM,Sun的工作重点是动态语言,而不是功能语言。

因此,有一个非常有力的论据认为Scala不是真正的函数式编程语言:自从Scheme在30多年前首次引入以来,这些语言就将尾调用视为必不可少的功能。


5
Hence there is a very strong argument that Scala is not a real functional programming language -这个论点实际上很弱。当然可以tail calls [as] an essential feature,如果基础硬件(或虚拟机)直接支持它,那就很好。但这是实现细节。
Ingo

8
@Ingo:仅当您不认为用户认为运行时程序中的堆栈溢出是一个重大问题时。根据它的错误跟踪器,甚至Scala编译器本身也受到堆栈溢出的困扰。因此,即使是经验最丰富的Scala开发人员也仍然会出错...
JD

7
倡导F#是可以的。但是我已经注意到您很长时间了(甚至在usenet中已经使用了很多年),因为他们对不是F#的所有内容都怀有敌意,但是您的细心表明您不知道自己在说什么。就像这里:您的论据似乎是一种我可以编写因堆栈溢出而中止的程序的语言,不是一种功能?但是,对于我会引起堆溢出的语言,难道不能使用相同的论点吗?因此,神圣的F#本身不算功能。
Ingo

7
@Ingo:函数式编程中的一些惯用法,例如相互递归和连续传递样式,可能需要消除尾部调用才能起作用。没有它,您的程序将堆栈溢出。如果一种语言不能可靠地运行惯用的功能代码,那么它是否起作用?正如您所说,答案是一个判断电话,但实际上却是一个重要区别。马丁·特罗耶(Martin Trojer)刚刚发表了一篇有趣的博客文章:martinsprogrammingblog.blogspot.com/2011/11/…–
JD

2
但是,仅因为JVM(很遗憾,没有问题)不能进行尾部调用,这并不意味着消除尾部调用是不可能的。这就好像有人说只有在装有FPU的计算机上才可以进行浮点计算。
Ingo

22

Scala 2.7.x支持尾部调用优化,以实现最终方法和局部函数的自递归(调用自身的函数)。

Scala 2.8也可能附带对蹦床的库支持,这是一种优化相互递归函数的技术。

可以在Rich Dougherty的博客中找到有关Scala递归状态的大量信息。


您能否更新有关当前Scala状态的问题?
om-nom-nom

@ om-nom-nom AFAIK,无论是在Scala方面还是在JVM方面,都没有任何改变。
Daniel C. Sobral


0

所有资料都指出JVM在尾部递归的情况下无法优化,但是在阅读Java性能调整(2003年,O'reilly)时,我发现作者声称他可以通过实现尾部递归来实现更高的递归性能。

您可以在第212页找到他的主张(搜索“ tail recursion”(尾递归)应该是第二个结果)。是什么赋予了?


IBM在其JVM实现中支持某种形式的TCO(作为优化,因此不能保证)。Java Performance Tuning的作者也许认为此功能最终将由所有JVM实施。ibm.com/developerworks/java/library/j-diag8.html
llemieng'2
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.