Java性能testing

我想在Java应用程序上做一些时间testing。 这是我目前正在做的事情:

long startTime = System.currentTimeMillis(); doSomething(); long finishTime = System.currentTimeMillis(); System.out.println("That took: " + (finishTime - startTime) + " ms"); 

这样的性能testing有什么“错误”吗? 什么是更好的方法?

重复 : 秒表基准testing是否可以接受?

这种方法的一个缺陷是, doSomething()执行所花费的“实际”时间可能会大不相同,这取决于系统上运行的其他程序以及它的负载是什么。 这使得性能测量有些不准确。

跟踪执行代码所需时间的一种更精确的方法是假设代码是单线程的,那就是查看调用期间线程所占用的CPU时间。 你可以用JMX类来完成这个工作。 特别是使用ThreadMXBean 。 您可以从java.lang.management.ManagementFactory检索ThreadMXBean的实例,如果您的平台支持(大部分是),则使用getCurrentThreadCpuTime方法代替System.currentTimeMillis来执行类似的testing。 请记住, getCurrentThreadCpuTime报告的时间以纳秒为单位,而不是毫秒。

下面是一个可用于执行测量的示例(Scala)方法:

 def measureCpuTime(f: => Unit): java.time.Duration = { import java.lang.management.ManagementFactory.getThreadMXBean if (!getThreadMXBean.isThreadCpuTimeSupported) throw new UnsupportedOperationException( "JVM does not support measuring thread CPU-time") var finalCpuTime: Option[Long] = None val thread = new Thread { override def run(): Unit = { f finalCpuTime = Some(getThreadMXBean.getThreadCpuTime( Thread.currentThread.getId)) } } thread.start() while (finalCpuTime.isEmpty && thread.isAlive) { Thread.sleep(100) } java.time.Duration.ofNanos(finalCpuTime.getOrElse { throw new Exception("Operation never returned, and the thread is dead " + "(perhaps an unhandled exception occurred)") }) } 

(随意将上面的内容翻译成Java!)

这个策略并不完美,但是不太受系统负载变化的影响。

问题中显示的代码不是一个好的性能测量代码:

  1. 编译器可能会select通过重新sorting语句来优化您的代码。 是的,它可以做到这一点。 这意味着您的整个testing可能会失败。 它甚至可以select内联testing方法,并将测量语句重新sorting为现在的内嵌代码。

  2. 热点可能会select重新sorting您的语句,内联代码,caching结果,延迟执行…

  3. 即使假设编译器/热点没有欺骗你,你测量的是“墙壁时间”。 你应该测量的是CPU时间(除非你使用操作系统资源,并且也希望包含这些资源,或者你在multithreading环境中测量锁竞争)。

解决scheme? 使用真实的分析器。 周围有很多,免费的个人资料和演示/时间locking的广告实力的审判。

使用Java Profiler是最好的select,它将为您提供代码中所需的所有信息。 即响应时间,线程CallTraces,内存利用率等

我会build议你JENSOR ,一个开源的Java Profiler,因为它的易用性和CPU上没有开销。 你可以下载它,仪器的代码,并会得到你所需要的关于你的代码的所有信息。

你可以从http://jensor.sourceforge.net/下载它:;

请记住, System.currentTimeMillis()的分辨率在不同的操作系统之间有所不同。 我相信Windows是大约15毫秒。 所以如果你的doSomething()比时间分辨率运行得快,你将得到一个0的增量。你可以在一个循环中多次运行doSomething() ,但是JVM可以优化它。

那么这只是性能testing的一部分。 根据你正在testing的东西,你可能不得不看堆的大小,线程数,networkingstream量或其他东西。 否则,我使用这种技术来做简单的事情,我只想看看他们需要多长时间才能运行。

当你将一个实现与另一个实现进行比较或试图在你的代码中find一个缓慢的部分的时候,这是很好的(尽pipe它可能很乏味)。 这是一个非常好的技术,你可能会比其他任何人都使用它,但也要熟悉一下分析工具。

你有没有看过netbeans和eclipse中的分析工具? 这些工具使您能够更好地处理代码中始终占用的内容。 我发现了使用这些工具没有意识到的问题。

我想你也想在开始计时之前做一些事情,这样代码就会被打乱并“热身”起来。

Japex可能对您有用,可以作为快速创build基准的一种方式,也可以作为通过源代码研究Java中的基准testing问题的方法。