测量代码段的 Java 执行时间、内存使用和 CPU 负载

Posted

技术标签:

【中文标题】测量代码段的 Java 执行时间、内存使用和 CPU 负载【英文标题】:Measuring Java execution time, memory usage and CPU load for a code segment 【发布时间】:2010-09-23 01:19:00 【问题描述】:

对于一段特定的 Java 代码,我想测量:

执行时间(很可能是线程执行时间 内存使用情况 CPU 负载(具体归因于代码段)

我是一个相对的 Java 新手,不熟悉如何实现这一点。我被推荐给了JMX,但我不确定如何使用它,而且 JMX 对于我想要做的事情看起来有点“沉重”。

理想情况下,我想要一些可以告诉我想要测量什么的测量类,可以选择在代码段之前调用start() 方法,在之后调用stop() 方法。相关指标将记录到我指定的文件中。

例如:

import com.example.metricLogger;

metricLogger logger = new metricLogger();

logger.setLogPath(pathToLogFile);
logger.monitor(executionTime);
logger.monitor(memoryUsage);
logger.monitor(cpuLoad);

logger.start();

/* Code to be measured */

logger.stop();

在 Java 中是否有任何标准/通用/常规方法可以实现这一点?

此类测量仅用于一次性性能比较,因此我不寻找任何生产中的长期监控流程。

我很高兴被提及教程或外部示例,并且不希望在这里得到完整的答案。也就是说,如果可以实现上述简单的任何事情,那么一个现实的例子就会非常成功。

【问题讨论】:

【参考方案1】:

分析可能是一个更简单的选择,因为您不需要生产中的统计信息。分析也不需要修改代码。 VisualVM(附带 JDK 1.6.06+)是一个简单的工具。如果您想要更深入的内容,我会使用 Eclipse TPTP、Netbeans profiler 或 JProfiler(pay)。

如果您想自己编写,请考虑以下几点:

执行时间等简单测量可以通过“计时”您感兴趣的部分来完成:

long start = System.nanoTime(); // requires java 1.5
// Segment to monitor
double elapsedTimeInSec = (System.nanoTime() - start) * 1.0e-9;

您可以使用类似的技术通过 Runtime.getRuntime().*memory() 方法监控内存。请记住,在垃圾收集环境中跟踪内存使用情况比简单的减法要复杂。

CPU 负载在 Java 中很难衡量,我通常坚持执行时间并优化较长/重复的部分

【讨论】:

其测量结果可能包括垃圾收集时间、JIT 编译器花费的时间、其他进程在操作系统中花费的时间、其他进程花费的时间或执行“要监控的段”可能比调用nanoTime() 的时间小两个数量级。仅仅因为nanoTime() 返回纳秒并不意味着它的分辨率如此之高。 OP 还要求测量内存使用情况。那些分析器可以测量吗? (我怀疑不是)【参考方案2】:

使用 ThreadMXBean,您可以获得单个线程的 CPU 使用率和消耗的 CPU 时间,而不是可能有用的经过时间。

但是,使用分析器通常更简单,因为此过程通常会生成大量数据,您需要一个良好的可视化工具来查看发生了什么。

我使用 Yourkit,因为我发现解决我使用过的其他分析器的问题更容易。 我还使用了内置的 hprof,因为这可以让您对应用程序的配置文件有不同的看法(但没那么有用)

【讨论】:

另请参阅有关 ThreadMXBean 的教程:nadeausoftware.com/articles/2008/03/…【参考方案3】:

使用 Java Profiler 是最好的选择,它可以让您深入了解代码。即响应时间、线程调用跟踪、内存利用率等

我会推荐你​​JENSOR,这是一个开源的 Java Profiler,因为它易于使用且 CPU 开销低。您可以下载它,检测代码并获得您需要的有关代码的所有信息。

您可以从以下地址下载:http://jensor.sourceforge.net/

【讨论】:

探查器不可能有 no cpu 开销。虽然这个可能有特别少的开销,但我不知道这个。【参考方案4】:

我们可以通过收集执行期间的 cpu 和内存指标来测量特定调用方法期间使用的 cpu 和内存。 当然,如果其他方法的其他并发线程在执行过程中消耗了内存和cpu,你就会卡住。因此,当您能够以隔离的方式执行方法时,这是一种有效的方法。

对于 CPU,你可以得到它的当前值:

OperatingSystemMXBean osBean = ManagementFactory.getPlatformMXBean(
            OperatingSystemMXBean.class); 
double processCpuLoad = osBean.getProcessCpuLoad();

为了内存,你可以这样做:

MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
int currentHeapUsedInMo = (int) (memoryMXBean.getHeapMemoryUsage().getUsed() / 1_000_000);

关于内存测量,在执行该方法之前等待一个主要收集提高了它的可靠性。

例如,类似的事情可能会有所帮助:

import com.google.common.testing.GcFinalization;

GcFinalization.awaitFullGc();
foo.execute(); // method to execute

GcFinalization 来自Guava test library。

所有这些都几乎没有开销。因此,想法是为您要监视的每个调用方法收集指标(例如每秒),并在方法返回时计算最大值/平均值或任何有用的信息。

我希望 AOP 这样做。 Spring AOP 是一种创建切面并为其设置切入点的简单而好方法,但如果您需要一些关于 AOP 特性的特定内容,也可以使用 AspectJ 来完成。

【讨论】:

以上是关于测量代码段的 Java 执行时间、内存使用和 CPU 负载的主要内容,如果未能解决你的问题,请参考以下文章

java线程基础梳理

测量执行时间和使用的内存

如何测量数据结构的内存使用情况? [复制]

获取STM32代码运行时间的技巧

java程序性能调优---------------性能概述

数据段代码段堆栈段BSS段的区别