在Java中尝试捕获静态方法的慢度
我正在查看以下讨论: 在实验中,我发现如果我运行静态方法而不是实例方法,那么普通路径实际上比try-catch-path花费更多的时间 我正在做的是:创建一个无操作静态在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 {
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
- 首先运行的版本往往较慢。这可能与热点编译器“预热”有关,但我不是热点内部的专家
-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