如何衡量方法分配率?

how to measure method allocation rate?

是否有针对 JVM 的分析器或工具(jconsolejfrVisualVM、...)显示其分配率的方法?

我的意思是,像这样

org.package1.Class1.method1, 145k
org.package2.Class3.method5, 34k

此外,我正在寻找一种方法来查看哪些方法因分配暂停而被中断最多。

也许不可能,或者没有意义。但这只是为了 gc 学习目的,我想进一步调查。

JDK 飞行记录器 (JFR) 可以测量每个分配站点(方法)的分配率,但它是基于样本的,因此它以准确性换取开销。你需要几千个样本。为每个分配记录堆栈跟踪(或方法)的开销是巨大的,并且会使应用程序停止。

JDK16引入了一个新的事件(ObjectAllocationSample),它限制了每秒的事件数。您应该能够在 JMC 中看到它。如果没有,这里有一个小程序,可以为您提供每个方法的分配直方图。

import java.io.IOException;
import java.nio.file.Path;
import java.util.*;
import jdk.jfr.consumer.*;

public class AllocationHistogram {
  public static void main(String[] args) throws IOException {
    if (args.length != 1) {
      System.err.println("Must specify a recording file.");
      return;
    }
    Map<String, Long> histogram = new HashMap<>();
    try (var es = EventStream.openFile(Path.of(args[0]))) {
      es.onEvent("jdk.ObjectAllocationSample", e -> {
        RecordedStackTrace s = e.getStackTrace();
        if (s != null) {
          RecordedFrame topFrame = s.getFrames().get(0);
          if (topFrame.isJavaFrame()) {
            RecordedMethod m = topFrame.getMethod();
            String className = m.getType().getName();
            String key = className + "." + m.getName();
            histogram.merge(key, e.getLong("weight"), (a, b) -> a + b);
           }
         }
       });
       es.start();
    }
    var list = new ArrayList<>(histogram.entrySet());
    list.sort(Map.Entry.<String, Long>comparingByValue().reversed());

    for (var entry : list) {
      System.out.printf("%12dk %s\n", entry.getValue() /1024, entry.getKey());
    }
  }
}

用法:

$ java -XX:StartFlightRecording:filename=recording.jfr ...
$ # Stop the program after two minutes (CTRL+C)
$ java AllocationHistogram.java recording.jfr

16688k java.util.HashMap.newNode 
 1022k java.lang.AbstractStringBuilder.<init>
  511k java.lang.Long.valueOf 
   ... ...