了解 JMH Java 中的 GC 分析器

问题描述 投票:0回答:1

我正在使用 Java Microbenchmarking Harness 运行一些实验,特别是我正在使用 GC 分析器。关于解释 GC 分析器的结果,我有三个问题。

这是我的基准:

@Benchmark
    public void benchmarkPiecewiseDNFModel(Blackhole blackhole) {
        // Run the method and consume the output to avoid dead code elimination
        PiecewiseCausalModel model = creator.PiecewiseDNFModel(users);
        blackhole.consume(model);
    }

基准测试中的方法创建了大量析取范式形式的布尔公式。对于该基准测试的单次运行,通过一次预热,我获得了以下结果:

Benchmark                                                           (users)  Mode  Cnt            Score   Error   Units
BenchmarkModelCreator.benchmarkPiecewiseDNFModel                         650    ss                77.664            s/op
BenchmarkModelCreator.benchmarkPiecewiseDNFModel:gc.alloc.rate           650    ss               809.123          MB/sec
BenchmarkModelCreator.benchmarkPiecewiseDNFModel:gc.alloc.rate.norm      650    ss       65892091888.000            B/op
BenchmarkModelCreator.benchmarkPiecewiseDNFModel:gc.count                650    ss                61.000          counts
BenchmarkModelCreator.benchmarkPiecewiseDNFModel:gc.time                 650    ss               332.000              ms

我试图在该基准测试的单次测量迭代的背景下解释这些结果。我似乎无法找到以下问题的明确答案:

(1) GC 分析器测量的具体是什么,尤其是在 gc.alloc.rate.norm 中? 报告的 65 GB 是一个累积数字,因此 GC 分析器似乎是求和在每个垃圾收集事件之前增加内存分配?准确吗?这是我的操作每秒分配的平均内存量吗?

(2) 准确地说,操作是如何定义的? 特别是,操作是我的基准测试(creator.PiecewiseDNFModel)中方法的单次调用吗?或者,操作是否以更细粒度的方式定义来处理 PiecewiseDNFModel 本身的不同部分?

(3) 使用 GC 分析器来测量一段代码的内存占用量(考虑到其累积测量方法),这不是有点误导吗? 例如,如果我有一个操作恰好需要很长时间,但是比如说,在给定时刻仅用完 100MB,那么 GC 分析器将报告大量的 gc.alloc.rate.norm,但该进程在我的机器上的实际负担非常低。似乎一个在任何时候报告最大内存使用情况的分析器更合适。如果这是正确的(我愿意接受反对),那么任何人都可以建议一种更合适的分析方法吗?

我预先感谢您就这三点提供的澄清。

java garbage-collection benchmarking microbenchmark jmh
1个回答
0
投票

第二个问题的答案是,“操作”是每次调用

@Benchmark
方法(除非您通过用
@OperationsPerInvocation
注释该方法来覆盖它),所以是的,在您的情况下,它是调用次数到
creator.PiecewiseDNFModel

关于您的第一个问题,据报告,gc.alloc.rate 是您的方法分配的 MB/秒数。 gc.alloc.rate.norm 是调用的每个“操作”(如上所述)分配的字节数。 这些都是(据我理解)使用相同分子的计算。

关于你的第三个问题...

对于一个对象,我们可以将其视为存在两种状态之一 - 使用中垃圾。 “正在使用”的对象是“可访问的”并且将来可能被程序使用的对象。 如果一个对象不可访问,但尚未被收集,则该对象是“垃圾”。 (还有第三种状态leaked,一个对象如果可达,则具有leaked,不会变得不可达,但永远不会再次使用,但这对于本次讨论来说不是必要的)。 在运行垃圾收集之前,我们无法知道对象是否是垃圾。 (据我所知,在Java中,没有办法在不执行收集的情况下运行分析)。 因此,JMH 无法区分在操作期间分配 50 MB 的代码 (c1)(所有这些在操作退出之前都在使用中)和分配的代码 (c2),它们立即导致无法访问,10 MB,但执行了 5 次每次操作。 在这两种情况下,操作都分配了 50 MB,这就是 JMH 分析器所知道的全部内容。 也就是说,像 JMH 这样的东西的主要目的是帮助您比较同一“事物”的两个(或多个)不同实现。 大多数情况下,有趣的是这些分数的相对差异,而不是绝对数字。

© www.soinside.com 2019 - 2024. All rights reserved.