Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/308.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_Performance_Static_Try Catch - Fatal编程技术网

在Java中尝试捕获静态方法的慢度

在Java中尝试捕获静态方法的慢度,java,performance,static,try-catch,Java,Performance,Static,Try Catch,我正在查看以下讨论: 在实验中,我发现如果我运行静态方法而不是实例方法,那么普通路径实际上比try-catch-path花费更多的时间 我正在做的是:创建一个无操作静态foo()方法,创建一个静态方法method1(),它通常调用foo()100000000次,另一个静态方法method2()在try-catch块中调用foo()100000000次。我看到的是,method2实际上比method1花费的时间更少 有什么想法吗 public class ExceptionsStatic {

我正在查看以下讨论: 在实验中,我发现如果我运行静态方法而不是实例方法,那么普通路径实际上比try-catch-path花费更多的时间

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

有什么想法吗

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

    static void foo()
    {

    }

    static void foo2() throws Exception
    {

    }

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

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

            }
        }

        long t2 = System.currentTimeMillis();

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

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

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

        long t2 = System.currentTimeMillis();

        System.out.println("normal time taken " + (t2 - t1));
    }
}
公共类例外静态
{
公共静态void main(字符串…参数)
{               
with normal();
withTry();
}
静态void foo()
{
}
静态void foo2()引发异常
{
}
静态void withTry()
{
long t1=System.currentTimeMillis();
对于(int i=0;i<100000000;i++)
{
尝试
{
foo2();
}
捕获(例外e)
{
}
}
long t2=System.currentTimeMillis();
System.out.println(“try time take”+(t2-t1));
}
带法线的静态void()
{
long t1=System.currentTimeMillis();
对于(int i=0;i<100000000;i++)
{
foo();
}
long t2=System.currentTimeMillis();
System.out.println(“正常时间”+(t2-t1));
}
}

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

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

当然,正如Joachim在下面提到的,“字节码对性能的影响很小”

有很多标志可用于分析和启用/禁用JVM优化。在网上四处看看。对于1.4.2,我发现这可能也适用于较新的JRE

编辑为添加:在受支持的虚拟机中,您可以使用以下虚拟机标志
-XX:-printcomilation
,启用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


}
Ryan-Schippers-MacBook-Pro-2:杂项工作$javap-c-classpath./src SlowTryCatch
从“SlowTryCatch.java”编译而来
公共类SlowTryCatch扩展了java.lang.Object{
公共SlowTryCatch();
代码:
0:aload_0
1:invokespecial#1;//方法java/lang/Object。“:()V
4:返回
公共静态void main(java.lang.String[]);
代码:
0:返回
公共静态void foo();
代码:
0:返回
公共静态无效方法1();
代码:
0:iconst_0
1:istore_0
2:iload_0
3:ldc#2;//int 100000000
5:if_icmpge 17
8:invokestatic#3;//方法foo:()V
11:iinc 0,1
14:goto 2
17:返回
公共静态无效方法2();
代码:
0:iconst_0
1:istore_0
2:iload_0
3:ldc#2;//int 100000000
5:if_icmpge 21
8:invokestatic#3;//方法foo:()V
11:goto 15
14:astore_1
15:iinc 0,1
18:goto 2
21:返回
例外情况表:
从到目标类型
8 11 14类java/lang/Exception
}

我对您的代码进行了一些修改,以便优化器不会删除代码。通过在Sun/Oracle JVM中多次运行,我发现:

  • 执行时间是不确定的。这在热点JVM中很常见,尤其是在多核系统中
  • withNormal()
    withTry
    之间的差异最小。这是意料之中的,因为没有实际的异常抛出,也没有
    finally
  • 首先运行的版本往往较慢。这可能与热点编译器“预热”有关,但我不是热点内部的专家
总而言之,我不希望使用异常的代码与不使用异常的代码之间有任何显著差异,当在Sun/Oracle JVM中运行时,很可能是来自热点的噪声

更新

我使用
-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);
}
公共类例外静态{
公共静态void main(字符串…参数)
{
with normal();
withTry();
}
静态int-fooVar;
静态void foo()
{
fooVar++;
}
静态int-foo2Var;
静态void foo2()引发异常
{
foo2Var++;
}
静态void withTry()
{
long t1=System.currentTimeMillis();
foo2Var=0;
对于(int i=0;i<100000000;i++)
{
尝试
{
foo2();
}
捕获(例外e)
{
}
}
long t2=System.currentTimeMillis();
System.out.println(“try time take”+(t2-t1)+“;”+foo2Var);
}
带法线的静态void()
{
long t1=System.currentTimeMillis();
fooVar=0;
对于(int i=0;i<100000000;i++)
{
foo();
}
long t2=System.currentTimeMillis();
System.out.println(“正常时间”+(t2-t1)+“;”+fooVar);
}

这里有一个吸吮更少的微基准。使用
1
2
作为程序参数,使用
-XX:+printcomployment-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++;
    }
}
公共类TryBlockBenchmark{
专用静态最终int测量值=100;
私有静态int-dummy=0;
公共静态void main(字符串[]args){
布尔tryBlock=args[0]。等于(“1”);
System.out.println(tryBlock?“try block”:“no try block”);
对于(int i=0;i