使用性能分析(Profiling/Instrumentation)获取方法调用次数
为什么需要 Profiling采样(Sampling)是性能分析的起点,它能快速呈现应用执行的整体视图——哪些方法在执行、总耗时大致多少。但采样有一个关键局限:它只告诉你方法占用了多少时间,却无法告诉你这个方法被调用了多少次。举个例子:一个方法单次执行只需要 50 毫秒,但如果在某个功能中被重复调用了 1000 次,总耗时就会达到 50 秒。采样只会显示该方法总共占用了 50 秒,而不会告诉你是因为重复调用导致的。这种场景下,如果只依赖采样,你很可能会误判:以为是算法本身慢,却忽略了“重复执行”这个真正的根因。Profiling(也叫 Instrumentation)就是为了弥补这个不足而生的。它能精确记录每一个方法的调用次数、每次执行的时间,让你看清到底是“慢”还是“多”。Profiling 的适用场景Profiling 不应该替代采样,而是采样的后续步骤。在采样已经帮你锁定了“嫌疑区域”之后——比如某个端点响应慢,而堆栈显示大部分时间花在某个包的类中——你就可以用 Profiling 对这片区域进行“显微镜式”分析。典型适用场景包括:发现某个方法总耗时异常高,但不确定是一次慢调用还是多次快调用。怀疑框架或依赖库动态生成的代码存在重复调用(例如 Feign 客户端、JPA 代理等)。调优已知逻辑,验证重构后调用次数是否减少。实操步骤:在 VisualVM 中配置 Profiling 过滤规则以 VisualVM 为例,Profiling 需要在Profiler标签页中进行。关键步骤:启动应用和 VisualVM,确保应用以-Djava.rmi.server.hostname=localhost启动以便连接。在左侧进程列表中选中目标进程,切换到Profiler标签。默认情况下,Profiling 会拦截整个应用的所有类,这会导致巨大的性能开销。必须手动限定范围:在右侧的过滤框中输入需要分析的包或类。过滤规则语法非常简单:# 匹配单个包下的所有类 com.example.* # 匹配包及其所有子包 com.example.** # 匹配具体类名 com.example.controllers.DemoController每条规则单独一行。对于 Spring 应用,通常需要同时分析应用自己的代码和关键依赖(如feign.**