Java中的静态方法的try-catch慢度

时间:2011-09-30 05:56:11

标签: java performance static try-catch

我正在查看此讨论:How slow are Java exceptions? 在进行实验时,发现如果我运行静态方法而不是实例方法,那么正常路径实际上比try-catch路径花费更多时间。

我正在做的是:创建一个无操作的静态foo()方法,创建静态方法method1(),正常地调用{100}次,另一个静态方法foo()在try-catch块中调用method2() 100000000次。我看到的是,foo()实际上花费的时间少于method2

有什么想法?

method1

3 个答案:

答案 0 :(得分:2)

我试图重新创建您的测试代码,然后通过javap运行它。这些是在最后给出的,因此您不必滚动大文本块。

请注意,当VM没有完全没有执行优化时,字节码将按照下面的javap转储执行。因此,假设没有其他外部因素,method2()的执行总是需要更长的时间,因为它包含一条额外的指令(line 11: goto 15)。

当然,正如Joachim在下面提到的那样,“字节码对性能的描述很少。”

有很多标记可用于分析和启用/禁用JVM优化。在网上浏览一下。对于1.4.2,我发现这个link也适用于较新的JRE。

编辑添加:在支持的VM中,您可以使用以下VM标记-XX:-PrintCompilation启用JIT跟踪输出。


javap输出:

Ryan-Schippers-MacBook-Pro-2:Miscellaneous work$ javap -c -classpath ./src SlowTryCatch
Compiled from "SlowTryCatch.java"
public class SlowTryCatch extends java.lang.Object{
public SlowTryCatch();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[]);
  Code:
   0:   return

public static void foo();
  Code:
   0:   return

public static void method1();
  Code:
   0:   iconst_0
   1:   istore_0
   2:   iload_0
   3:   ldc #2; //int 100000000
   5:   if_icmpge   17
   8:   invokestatic    #3; //Method foo:()V
   11:  iinc    0, 1
   14:  goto    2
   17:  return

public static void method2();
  Code:
   0:   iconst_0
   1:   istore_0
   2:   iload_0
   3:   ldc #2; //int 100000000
   5:   if_icmpge   21
   8:   invokestatic    #3; //Method foo:()V
   11:  goto    15
   14:  astore_1
   15:  iinc    0, 1
   18:  goto    2
   21:  return
  Exception table:
   from   to  target type
     8    11    14   Class java/lang/Exception


}

答案 1 :(得分:0)

我已经修改了一些代码,因此优化器不会删除代码。通过在Sun / Oracle JVM中运行它几次,我发现的是:

  • 执行时间不确定。这在HotSpot JVM中很常见,特别是在多核系统中
  • withNormal()withTry之间的差异很小。这是预期的,因为没有抛出任何实际异常,并且没有finally块。
  • 首先运行的版本往往较慢。它可能与HotSpot编译器“热身”有关,但我不是HotSpot内部的专家

总而言之,我不希望使用异常的代码之间有任何显着差异,在Sun / Oracle JVM中运行时,很可能是来自HotSpot的噪音。

<强>更新

我使用-server-client标志运行它,除了执行速度在我的机器中快一个数量级之外,上述观察结果也适用。

以下修改后的代码:

public class ExceptionsStatic    {

public static void main(String... args)
{
    withNormal();
    withTry();
}

static int fooVar;
static void foo()
{
    fooVar++;
}

static int foo2Var;
static void foo2() throws Exception
{
    foo2Var++;
}

static void withTry()
{
    long t1 = System.currentTimeMillis();

    foo2Var = 0;
    for(int i = 0; i < 100000000; i++)
    {
        try
        {
            foo2();
        }
        catch(Exception e)
        {

        }
    }

    long t2 = System.currentTimeMillis();

    System.out.println("try time taken " + (t2 - t1) + "; " + foo2Var);
}

static void withNormal()
{
    long t1 = System.currentTimeMillis();

    fooVar = 0;
    for(int i = 0; i < 100000000; i++)
    {
        foo();
    }

    long t2 = System.currentTimeMillis();

    System.out.println("normal time taken " + (t2 - t1) + "; " + fooVar);
}

答案 2 :(得分:0)

这是一个微不足道的基准测试。使用12作为程序参数,使用-XX:+PrintCompilation -verbose:class -verbose:gc作为JVM参数。

public class TryBlockBenchmark {
    private static final int MEASUREMENTS = 100;
    private static int dummy = 0;

    public static void main(String[] args) {
        boolean tryBlock = args[0].equals("1");
        System.out.println(tryBlock ? "try block" : "no try block");

        for (int i = 0; i < MEASUREMENTS; i++) {

            long start = System.currentTimeMillis();
            if (tryBlock) {
                benchmarkTryBlock();
            } else {
                benchmarkNoTryBlock();
            }
            long end = System.currentTimeMillis();

            System.out.println((end - start) + " ms");
        }

        System.out.println("(" + dummy + ")");
    }

    private static void benchmarkTryBlock() {
        for (int i = Integer.MIN_VALUE; i < Integer.MAX_VALUE; i++) {
            try {
                staticMethod();
            } catch (Exception e) {
            }
        }
    }

    private static void benchmarkNoTryBlock() {
        for (int i = Integer.MIN_VALUE; i < Integer.MAX_VALUE; i++) {
            staticMethod();
        }
    }

    private static void staticMethod() {
        dummy++;
    }
}

在C2Q6600 @ 3GHz上使用Java 1.6.0_24 64位HotSpot Server VM,在第一次测量之后,两个版本的时间稳定在266 ms(+/- 1 ms)。手动内联staticMethod()时的时间也相同,这可以从HotSpot预期。当HotSpot将其优化时,删除dummy++行会将时间减少到0毫秒。

我还使用32位的Java 1.6.0_24进行了测试,并且HotSpot Server VM具有相同的结果,但HotSpot Client VM的两个版本产生的结果大约为8660毫秒(+/- 20毫秒)。

因此,我们可以得出结论,服务器VM具有比客户端VM更好的优化,并且没有做任何事情的try-catch要么被HotSpot优化掉,要么它不会影响性能。要查找它是什么,由HotSpot生成print the assembly code

总的来说,衡量一无所获的事情是毫无意义的。