Android:运行一个空方法会产生多less开销?

我创build了一个类来处理我的debugging输出,所以我不需要在发布之前去掉所有的日志输出。

public class Debug { public static void debug( String module, String message) { if( Release.DEBUG ) Log.d(module, message); } } 

在阅读另一个问题之后,我了解到,如果常量Release.DEBUG为false,则不会编译if语句的内容。

我想知道的是运行这个空方法产生多less开销? (一旦if子句被删除,方法中就没有代码了)是否对我的应用程序有任何影响? 当写手机= P时,显然性能是一个大问题

谢谢

加里

Solutions Collecting From Web of "Android:运行一个空方法会产生多less开销?"

使用Android 2.3.2在Nexus S上进行的测量:

 10^6 iterations of 1000 calls to an empty static void function: 21s <==> 21ns/call 10^6 iterations of 1000 calls to an empty non-static void function: 65s <==> 65ns/call 10^6 iterations of 500 calls to an empty static void function: 3.5s <==> 7ns/call 10^6 iterations of 500 calls to an empty non-static void function: 28s <==> 56ns/call 10^6 iterations of 100 calls to an empty static void function: 2.4s <==> 24ns/call 10^6 iterations of 100 calls to an empty non-static void function: 2.9s <==> 29ns/call 

控制:

 10^6 iterations of an empty loop: 41ms <==> 41ns/iteration 10^7 iterations of an empty loop: 560ms <==> 56ns/iteration 10^9 iterations of an empty loop: 9300ms <==> 9.3ns/iteration 

我重复了几次测量。 没有发现显着的偏差。 您可以看到每个通话费用可能会因工作负载而有很大差异(可能是由于JIT编译),但可以得出3个结论:

  1. 达尔维克/ java糟糕的优化死代码

  2. 静态函数调用可以优化得比非静态函数好得多(非静态函数是虚拟的,需要在虚拟表中查找)

  3. 联系上的成本不大于70ns /次(这就是〜70cpu周期),并且与一个空循环迭代的成本相当(即对一个局部variables的一个增量和一个条件检查)

注意,在你的情况下,string参数将始终被评估。 如果你做string连接,这将涉及创build中间string。 这将是非常昂贵的,涉及到很多gc。 例如执行一个函数:

 void empty(String string){ } 

用诸如

 empty("Hello " + 42 + " this is a string " + count ); 

100个这样的调用的10 ^ 4次迭代需要10s。 那就是10us /通话,比只是一个空的通话慢了1000倍。 它也产生大量的GC活动。 避免这种情况的唯一方法是手动内联函数,即使用>> if <<语句代替debugging函数调用。 这是丑陋的,但唯一的方法,使其工作。

除非你在深度嵌套循环中调用它,否则我不会担心。

一个好的编译器会删除整个空的方法,根本没有任何开销。 我不确定Dalvik编译器是否已经做到了这一点,但是我怀疑,至less从Froyo的Just-in-time编译器到来之后可能。

另见: 内联扩展

在性能方面,生成传递给debugging函数的消息的开销会更加严重,因为它可能会执行内存分配

 Debug.debug(mymodule, "My error message" + myerrorcode); 

即使通过邮件分类仍会发生。 不幸的是,如果你的目标是性能,你真的需要围绕调用这个函数的“if(Release.DEBUG)”,而不是在函数本身内部,你会看到很多的android代码。

这是一个有趣的问题,我喜欢@misiu_mp分析,所以我想我会在运行Android 6.0.1的Nexus 7上进行2016testing。 这里是testing代码:

 public void runSpeedTest() { long startTime; long[] times = new long[100000]; long[] staticTimes = new long[100000]; for (int i = 0; i < times.length; i++) { startTime = System.nanoTime(); for (int j = 0; j < 1000; j++) { emptyMethod(); } times[i] = (System.nanoTime() - startTime) / 1000; startTime = System.nanoTime(); for (int j = 0; j < 1000; j++) { emptyStaticMethod(); } staticTimes[i] = (System.nanoTime() - startTime) / 1000; } int timesSum = 0; for (int i = 0; i < times.length; i++) { timesSum += times[i]; Log.d("status", "time," + times[i]); sleep(); } int timesStaticSum = 0; for (int i = 0; i < times.length; i++) { timesStaticSum += staticTimes[i]; Log.d("status", "statictime," + staticTimes[i]); sleep(); } sleep(); Log.d("status", "final speed = " + (timesSum / times.length)); Log.d("status", "final static speed = " + (timesStaticSum / times.length)); } private void sleep() { try { Thread.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } private void emptyMethod() { } private static void emptyStaticMethod() { } 

sleep()被添加以防止溢出Log.d缓冲区。

我玩了很多次,结果与@misiu_mp非常一致:

 10^5 iterations of 1000 calls to an empty static void function: 29ns/call 10^5 iterations of 1000 calls to an empty non-static void function: 34ns/call 

静态方法调用总是比非静态方法调用稍微快一些,但似乎a)自Android 2.3.2以来,差距已经显着地closures了,b)调用空方法仍然有成本,不。

看着时间的直方图揭示了一些有趣的事情,但是。 大部分的电话,无论是否静止,需要30-40ns,仔细观察数据,他们几乎全部是30ns。

在这里输入图像说明

使用空循环运行相同的代码(注释掉方法调用)会产生8ns的平均速度,然而,大约3/4的测量时间是0ns,而其余的正好是30ns。

我不知道如何解释这些数据,但我不确定@ misiu_mp的结论是否成立。 空静态和非静态方法之间的差异可以忽略不计,测量的优势正好是30ns。 这就是说,看来运行空方法仍然存在一些非零成本。