java System.nanoTime非常慢。 是否可以实现高性能的Java分析器?

我做了一个测试,发现我的机器上对System.nanoTime()的函数调用开销至少为500 ns。

看来很难拥有一个高性能的Java分析器。 对于企业软件,假设一个函数大约需要350秒,并且有12,500,000,000次方法调用。 因此,对System.nanoTime()的调用次数为:12,500,000,000 * 2 = 25,000,000,000(一个用于开始时间戳,一个用于结束时间戳)并且System.nanoTime的总开销为:500 ns * 25,000,000,000 = 500 * 25000 s = 12500000s。

注意:所有数据来自实际案例。

有没有更好的方法来获取时间戳?

我花了10年时间研究商业Java性能分析器,用于开发和生产。

简短的回答是 – 是的,你是对的。 你不能把它拉下来。 即使你可以,将一些除了琐碎的工具之外的东西放入一个经常调用的方法中可以:

  • 因此,改变JIT处理代码的方式
  • 从性能调整的角度来看,难以预测性能数据(但通常没有用)。

    (并且让我们不要开始讨论如何在JIT完成之后在基本上紧凑的程序集循环中进行系统调用会影响CPU在预取方面可能做的所有花哨的优化,从而导致其他不必要的上下文切换和刷新你的L1缓存等等)

可以慢速(也可能是“不经常被称为’会更好?)方法。 您可以使用仪器,例如,许多JDBC API来捕获数据库问题。

对于实际Java代码的实际性能调优(与Java调用的东西相反,比如网络,文件系统,数据库……),工具实际上并不是真正的方法。 你得到了更多可以理解的结果,但是现在大概7年没有人为性能调整做过线级检测 – 原因相同。

相反,商业剖析器使用“采样”技术 – 他们会定期进行堆栈跟踪。 JVMTI有一些很好的调用,每隔几毫秒就可以很便宜。 然后你假设堆栈跟踪之间的所有时间花费在新堆栈上(显然,这不是真的,但从统计上来说,它会在非愚蠢的短测量时间内产生准确的结果) – 而且你已经得到了一些可操作的性能数字,没有疯狂的开销或任何观察者的影响。

一个实用的建议:不要在方法中调用System.nanoTime(),而是将其放在调用此方法的循环之外。

但是,这里有一个更深层的观点:你说你有一个被多次调用的方法,并且对这个方法添加两个System.nanoTimes()调用会使它非常慢。 根据您提供的数据,您的方法比几个Systme.nanoTime()调用快了35,000倍(12500000s / 350s = ~35,000)。

这是一种非常快速的方法。 它运行不到纳米。 我认为你不能让它更快。 等待您的唯一性能增益是基于减少调用此方法的次数(而不是通过使单个方法更快)。

数据可能不准确吗?

如果你想要分析,使用一个分析器,它将使用JVMTI准神奇地挂钩到JVM,而不需要将nanoTime()调用阻塞到代码中。

如果你想要微基准测试,只需循环许多次,这样当你将结果除以该数字时,nanoTime()开销几乎消失了。

System.nanoTime的总开销为:500 ns * 25,000,000,000 = 500 * 25000 s = 12500000s。

通过我的算术:

500 nS * 25,000,000,000 = 12500 S. 

因为:

 (500 * 10^-9) * (25 * 10^9) = 500 * 25