我试图找出哪些方法(尤其是在主线程上)需要一秒钟以上的时间才能执行。不幸的是,我正在使用 DDMS 和 traceview,但我并不真正了解如何读取提供的数据。有没有一种简单的方法可以找到长时间运行的方法?
11 回答
@Jake Wharton 刚刚发布了Hugo,它允许您注释方法并在 logcat 中接收这些方法的运行时间。
您可以简单地打印每次调用方法时的时间以及方法名称。然后您只需查看前一个时间戳之间的差异何时超过您想要的时间(1 秒)
Calendar c = Calendar.getInstance();
int seconds = c.get(Calendar.SECOND);
您可以使用SystemClock
该类来计算函数调用之前/之后的时间差异。
long time_start = SystemClock.elapsedRealtime();
myFunction();
long time_end = SystemClock.elapsedRealtime();
long diff = (time_end - time_start) / 1000;
Log.i("mytag", "Time Difference: " + diff + " seconds");
文档:http: //developer.android.com/reference/android/os/SystemClock.html
我认为最快的方法是简单地在调试器中运行你的程序。以随机间隔暂停它,然后只需注意暂停时程序正在执行的方法。
您在慢速方法中暂停的概率远高于在快速方法中暂停的概率。这意味着程序在您暂停时正在执行的方法是慢的。
有关更多信息,请参阅 Mike Dunlavey 对类似问题的出色回答: https ://stackoverflow.com/a/378024/1375762
有关如何使用 traceview 的教程:
请记住,网络或数据库调用可能需要很长时间,不应在主线程上调用,请使用后台线程或 AsyncTask 来完成这些调用。
除此之外,您可能会推出自己的时间测量辅助方法,如下所示(这是利用反射并以毫秒为单位返回方法调用时间):
public static long timeMethod(Method m, Object obj, Object... args) {
long start = 0, stop = 0;
try {
start = SystemClock.uptimeMillis();
m.invoke(obj, args);
stop = SystemClock.uptimeMillis();
} catch (Exception e) {
return ERROR;
}
return stop - start;
}
(错误只是-1,如果找不到具有指定参数的方法等,则会发生这种情况)
你知道StrictMode吗?每次在主线程上执行繁重的事情时,它都会在日志中打印。该报告包含以毫秒为单位的时间,因此您可以很容易地追踪冻结 UI 线程的代码。
除了 Calendar 和 SystemClock 类,还有我喜欢的第三个选项:Apache Commons StopWatch
您只需在方法的开头实例化该类并调用 StopWatch 的 start 方法,然后在方法的末尾调用它的 stop 方法。
然后 toString 方法会为您提供经过的时间。
好吧,没有一种最快的方法来计时功能,但可以精确而简单。
我认为如果你想精确,微秒可能是最好的选择:
long startTime = System.nanoTime();
// ... the code being measured ...
long estimatedTime = System.nanoTime() - startTime;
返回正在运行的 Java 虚拟机的高分辨率时间源的当前值,以纳秒为单位。
所以这是从JVM获得的,不一定是纳秒级的分辨率。正如预期的那样,这是测试函数执行时间的最准确方法。
此方法提供纳秒精度,但不一定提供纳秒分辨率(即值更改的频率) - 不保证分辨率至少与 currentTimeMillis() 的分辨率一样好。
http://docs.oracle.com/javase/7/docs/api/java/lang/System.html#nanoTime%28%29
您也可以尝试使用断点的调试器:http: //docs.oracle.com/javase/7/docs/technotes/tools/windows/jdb.html
您使用的是什么开发环境等?
您真正需要的是 Profiler。为您的开发和测试环境寻找一个合适的,分析器结果将告诉您方法被调用的频率以及调用的时间。
至于您的主要课程理念,您可以使用junit和上面的建议,方法是粘贴 Calendar.getTimeinMillis() 或 System.getNanoTime() 并在方法测试结束时执行减法。纳米时间更合适,因为以毫秒为单位的时间量对于一种方法来说可能是不存在的。您还可以从上面添加@Hugo 方法或您想要的任何其他方法。
将 junit 与您的 main 结合起来,但出于调试原因也通过测试用例运行所有内容。由于调试器可以减慢速度,因此更准确。
Junit 的好处是它适用于 Java 中的任何东西,甚至可以测试一定数量的迭代或执行断言。它可以完全控制您的测试,也允许您在方法内测试时间。它被包括英特尔在内的世界各地的公司使用。此外,它使您的代码保持干净,消除了一堆日志记录需求等,因为它是从一个单独的类运行的。
您的代码在您的测试类中如下所示:
//you could also use @Test(timeout=long)
@Test
public void testMethod()
{
YourClass test=new YourClass();
long s=System.getNanoTime();
//you could call your method directly here as well
assertEquals("name",50,test.yourMethod());
s=System.getNanoTime()-s;
}
有一个内置的 AndroidTimingLogger
类。
https://developer.android.com/reference/android/util/TimingLogger