如何衡量Java程序的效率(特别是汇编代码)?

5
我曾提出过一些问题,它们的答案通常指向效率方向。与其继续问这些类型的问题,我宁愿事先考虑效率。然而,当然有许多不同类型的效率。代码行数,汇编语言,编写时间,计算机执行时间等等。我可能忽略了很多其他的方式。
由于有这么多种方法来看待效率,我想先从如何获取自己代码的汇编代码以及停留在代码中的正确位置开始(假设你有500行代码,你感兴趣的是第450到460行)。我不确定这是否已经是IDE中存在的功能,如果是,我该如何找到这些函数?(=这些功能的命名是什么,以便我在自己的IDE中找到它们,如果它具备这个功能)。
(在Stack Overflow上已经有很多关于效率的信息,我看了很多,但我发现很难感受到人们在分析他们的代码时通常从哪里开始。他们是从研究自己的代码开始,然后再看汇编语言,还是只是使用IDE查找最昂贵的方法并以此更改呢?这是一个不好的问题,因为它当然取决于许多不同的因素,但我希望至少能够了解一点,并且我认为这个问题的答案可能有所帮助。)

1
调试器可以让你在特定的点(断点)停下来,然后从这些点单步执行或继续执行。通常情况下,人们使用调试器。对于较小的程序/问题,一些打印语句应该就能解决问题了(当然还需要进行一些检查和思考)。 - keyser
但是调试器只能让你停在特定的代码行,对吧?它并不能真正显示一个方法调用有多昂贵,仅显示该方法的源代码。使用打印语句意味着您打印开始时间和结束时间,并将其视为到达那里所需的时间。 - Joop
1
是的,它主要用于检查流程和内部工作情况。虽然也可以获取执行时间。调试时需要记住一件事,那就是实际代码经常会被更改以便进行调试,这可能会影响到您想要检查汇编或字节码的情况。 - keyser
2
我猜你要找的是性能分析器。JDK内置了一个叫做VisualVM的性能分析器,而且还有一些其他的免费和商业性能分析器可供选择。 - Simon
1
有另一种使用调试器的方法。您可以随机暂停它几次,看看正在发生什么假设它浪费了一些比例,例如30%的时间在做一些愚蠢的事情,比如调用某些无辜的函数,在调用堆栈的第5层中恰好执行一些文件I/O操作,您意识到您真的不需要它。如果您暂停10次,则平均有3次会为您解决问题。没有任何分析工具能够做到这一点。修复它,节省30%的时间,并重复此过程以获取下一个问题,依此类推。 - Mike Dunlavey
2个回答

4
您不太可能从分析JVM生成的汇编代码中获得任何有用的东西。如果您担心性能,那么这是错误的方法。您不能通过测量低级细节来推断高级性能。这在您可以手动计算周期的第一个程序中可能效果很好。现在的计算机要复杂得多 - 尤其是当您使用Java等高级语言时。需要考虑的事情包括:
垃圾收集器暂停
具有各种优化的JIT
多个级别的指令和数据缓存。
分支预测。
这些机制及其之间的相互作用并不是您可以轻易预测的。我知道只有一种明智的编写快速程序的方法:
编写程序的某个部分。
确定它确实太慢了。
识别并修复瓶颈。
返回步骤1。
为了识别瓶颈,我通常从JVisualVM开始,并在必要时使用一些更低级别的工具:

在99%的情况下,问题是算法慢、数据结构错误、磁盘访问效率低或者像残留的调试日志这样的愚蠢错误。不太常见的是微优化,比如避免不必要的复制或内存分配会有所帮助。在罕见的情况下,如果其他方法都失败了,你需要从紧密循环中挤出一些周期,那么看生成的汇编代码可能是值得的。PrintAssembly 在这种情况下可能有用。你应该从最有可能帮助你的工具开始。


2

要获取JVM的汇编代码,可以使用PrintAssembly参数。它提供了带有注释的可读代码,指向Java源代码中的行。因此,您可以清楚地了解您的Java代码是如何编译的。但我认为,查看处理器指令非常难以理解瓶颈。为此,我已经使用了VisualVM和JProfiler。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接