快速业务通道

诊断Java代码: 提高Java代码的性能 - 编程入门网

作者 佚名技术 来源 NET编程 浏览 发布时间 2012-06-19
)) {     return productHelp(i, accumulator * ((Integer)i.next()).intValue());    }    else {     return accumulator;    }   } } // And, in a separate file: import java.util.*; public class Example2 extends Example {   int productHelp(Iterator i, int accumulator) {    if (accumulator < 1) {     throw new RuntimeException("accumulator to productHelp must be >= 1");    }    else {     return super.productHelp(i, accumulator);    }   }   public static void main(String[] args) {    LinkedList l = new LinkedList();    l.add(new Integer(0));    new Example2().product(l.listIterator());   } }

类 Example2 中的被覆盖的 productHelp 方法试图通过当 accumulator 小于“1”时抛出运行时异常来捕捉对 productHelp 的不正确调用。不幸的是,这样做将引入一个新的错误。如果 Iterator 含有任何 0 值的实例,都将使 productHelp 在自身的递归调用上崩溃。

现在请注意,在类 Example2 的 main 方法中,创建了 Example2 的一个实例并调用了它的 product 方法。由于传给这个方法的 Iterator 包含一个 0,因此程序将崩溃。

然而,您可以看到类 Example 的 productHelp 是严格尾递归的。假设一个静态编译器想把这个方法的正文转换成一个循环,如清单 3 所示:

清单 3. 静态编译不会优化尾调用的一个示例

int productHelp(Iterator i, int accumulator) {    while (i.hasNext()) {     accumulator *= ((Integer)i.next()).intValue();    }    return accumulator;   }

于是,最初对 productHelp 的调用,结果成了对超类的方法的调用。超方法将通过简单地在 iterator 上循环来计算其结果。不会抛出任何异常。

用两个不同的静态编译器来编译这段代码,结果是一个会抛出异常,而另一个则不会,想想这是多么让人感到困惑。

诊断Java代码: 提高Java代码的性能(3)

时间:2011-02-11 IBM Eric E. Allen

您的 JIT 会做这种转换吗?

因此,如清单 3 中的示例所示,我们不能期望静态编译器会在保持语言语义的同时对 Java 代码执行尾递归转换。相反地,我们必须依靠 JIT 进行的动态编译。JIT 会不会做这种转换是取决于 JVM。

要判断您的 JIT 会否转换尾递归的一个办法是编译并运行如下小测试类:

清单 4. 判断您的 JIT 能否转换尾递归

public class TailRecursionTest {   private static int loop(int i) {    return loop(i);   }   public static void main(String[] args) {    loop(0);   } }

我们来考虑一下这个类的 loop 方法。这个方法只是尽可能长时间地对自身作递归调用。因为它永远不会返回,也不会以任何方式影响任何外部变量,因此如清单 5 所示替换其代码正文将保留程序的语义。

清单 5. 一个动态转换

public class TailRecursionTest {   private static int loop(int i) {    while (true) {    }   }   public static void main(String[] args) {    loop(0);   } }

而且,事实上这也就是足够完善的编译器所做的转换。

如果您的 JIT 编译器把尾递归调用转换成迭代,这个程序将无限期地运行下去。它所需的内存很小,而且不会随时间增加。

另一方面,如果 JIT 不做这种转换,程序将会很快耗尽堆栈空间并报告一个堆栈溢出错误。

我在两个 Java SDK 上运行这个程序,结果令人惊讶。在 SUN 公司的 Hotspot JVM(版本 1.3 )上运行时,发现 Hotspot 不执行这种转换。缺省设置下,在我的机器上运行时,不到一秒钟堆栈空间就被耗尽了。

另一方面,程序在 IBM 的 JVM(版本 1.3 )上

凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!

分享到: 更多

Copyright ©1999-2011 厦门凌众科技有限公司 厦门优通互联科技开发有限公司 All rights reserved

地址(ADD):厦门软件园二期望海路63号701E(东南融通旁) 邮编(ZIP):361008

电话:0592-5908028 传真:0592-5908039 咨询信箱:web@lingzhong.cn 咨询OICQ:173723134

《中华人民共和国增值电信业务经营许可证》闽B2-20100024  ICP备案:闽ICP备05037997号