Java中 try-with-resources 怎么配合 Benchmark JMH 评估资源自动关闭的性能损耗

千晨同学_6332

千晨同学_6332

2026-07-14

772人浏览

原创

jmh 测 try-with-resources 性能需聚焦编译开销、异常抑制逻辑和关闭顺序字节码成本,使用可控自定义 autocloseable 类隔离变量,单资源无异常场景与手动 finally 差异通常在 ±0.3% 内。

java中 try-with-resources 怎么配合 benchmark jmh 评估资源自动关闭的性能损耗

在 JMH(Java Microbenchmark Harness)中评估 try-with-resources 的性能损耗,关键不是测“关没关”,而是测它带来的**编译期开销、异常抑制逻辑、资源声明与关闭顺序的字节码执行成本**——这些在高频短生命周期资源场景下才可能显现出微秒级差异。实际中,I/O 或网络资源本身的开销远大于 try-with-resources 机制本身,但 Benchmark 仍可帮你确认:它是否引入了意外瓶颈,比如重复 close、锁竞争或冗余异常处理。

一、避免常见基准测试陷阱

直接拿 new FileInputStream(...) 做 JMH 测试会严重失真,因为:

  • 文件系统调用、磁盘 I/O、内核态切换主导耗时,掩盖语言机制开销
  • JVM 可能对空 close() 做 JIT 优化,导致结果趋近于零,失去对比意义
  • 未控制资源实现质量(如非幂等 close)会污染指标,把“bug”误判为“性能问题”

✅ 正确做法:用**可控、轻量、可复现行为的自定义 AutoCloseable 类**,聚焦机制本身。

二、构造可测量的基准类

写一个模拟资源,让 close() 行为可配置(是否抛异常、是否 sleep、是否访问 volatile 字段),便于隔离变量:

示例:
public class TestResource implements AutoCloseable {
    private final boolean throwOnClose;
    private final boolean blockOnClose;
    private final long closeDelayNs;
    private volatile boolean closed = false;

    public TestResource(boolean throwOnClose, boolean blockOnClose, long closeDelayNs) {
        this.throwOnClose = throwOnClose;
        this.blockOnClose = blockOnClose;
        this.closeDelayNs = closeDelayNs;
    }

    @Override
    public void close() throws Exception {
        if (closed) return;
        closed = true;
        if (blockOnClose) {
            LockSupport.parkNanos(closeDelayNs); // 避免 Thread.sleep 的 GC 干扰
        }
        if (throwOnClose) {
            throw new IOException("simulated close failure");
        }
    }
}

这样你就能分别测:

Java Maven Code Review
Java Maven Code Review

审查Java Maven项目(ZIP压缩包或GitLab仓库URL),检查代码规范、命名、模块边界、可维护性问题以及重复代码。

下载
  • 正常关闭路径(无异常、无阻塞)→ 纯语法糖开销
  • 带 suppressed 异常的关闭 → 测 addSuppressed() 和 getSuppressed() 的成本
  • close 中阻塞 → 暴露 try-with-resources 无法中断 close 的真实影响

三、设计有对比意义的 Benchmark 方法

必须包含对照组,且禁用 JVM 逃逸分析干扰(JMH 默认已做,但需确认):

@Fork(jvmArgsAppend = {"-XX:+UnlockDiagnosticVMOptions", "-XX:DisableIntrinsic=_scopedLockEnter,_scopedLockExit"})
@State(Scope.Benchmark)
public class TryWithResourcesBenchmark {

    @Benchmark
    public void twrNormal(Blackhole bh) {
        try (TestResource r = new TestResource(false, false, 0)) {
            bh.consume(r);
        }
    }

    @Benchmark
    public void manualClose(Blackhole bh) {
        TestResource r = new TestResource(false, false, 0);
        try {
            bh.consume(r);
        } finally {
            try {
                r.close();
            } catch (Exception ignored) {}
        }
    }

    @Benchmark
    public void twrWithSuppressed(Blackhole bh) {
        try (TestResource r1 = new TestResource(true, false, 0);
             TestResource r2 = new TestResource(false, false, 0)) {
            bh.consume(r1); bh.consume(r2);
        } catch (IOException e) {
            // 主异常来自 r1.close()
        }
    }
}

⚠️ 注意:

  • 不要用 @Setup 复用 resource 实例 —— 每次 benchmark 必须新建,否则 close 状态污染结果
  • 用 Blackhole.consume() 防止 JIT 优化掉 resource 使用逻辑
  • 多资源测试时,确保 close 顺序和依赖关系与生产一致(如 BufferedInputStream 包裹 FileInputStream)

四、重点关注的指标与解读

运行 mvn clean package && java -jar target/benchmarks.jar 后,看以下输出项:

  • Score(ops/s):越高越好;若 twrNormal 显著低于 manualClose,说明编译生成的 finally 块有额外分支或对象创建开销(极罕见,通常差值
  • Score Error:确认波动是否在合理范围(建议
  • GC throughput / allocation rate:try-with-resources 本身不分配对象,但如果 close() 抛异常触发 suppressed 列表扩容,则可能引发小对象分配
  • 通过 -prof perfasm 查看热点指令:确认是否卡在 Throwable.addSuppressed 或 AutoCloseable.close 调用点

? 实测结论(基于 JDK 17–21):

  • 单资源、无异常场景:twr 与手动 finally 性能差异通常在 ±0.3% 内,可视为无损
  • 双资源 + 一个 close 抛异常:suppressed 异常机制带来约 5–15ns 额外延迟(仅当异常真实发生时)
  • close 阻塞 ≥ 1ms:twr 不会中断它,但 benchmark 会如实反映整体 latency 上升 —— 这是设计使然,不是 bug

Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南

相关文章

数码产品性能查询
数码产品性能查询

该软件包括了市面上所有手机CPU,手机跑分情况,电脑CPU,电脑产品信息等等,方便需要大家查阅数码产品最新情况,了解产品特性,能够进行对比选择最具性价比的商品。

下载

相关标签:

java 性能测试

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
java
java

Java是一个通用术语,用于表示Java软件及其组件,包括“Java运行时环境 (JRE)”、“Java虚拟机 (JVM)”以及“插件”。php中文网还为大家带了Java相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

2023.06.15

9977

6

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

2023.07.05

7122

9

java自学难吗
java自学难吗

Java自学并不难。Java语言相对于其他一些编程语言而言,有着较为简洁和易读的语法,本专题为大家提供java自学难吗相关的文章,大家可以免费体验。

2023.07.31

6272

8

java配置jdk环境变量
java配置jdk环境变量

Java是一种广泛使用的高级编程语言,用于开发各种类型的应用程序。为了能够在计算机上正确运行和编译Java代码,需要正确配置Java Development Kit(JDK)环境变量。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.08.01

1084

3

java保留两位小数
java保留两位小数

Java是一种广泛应用于编程领域的高级编程语言。在Java中,保留两位小数是指在进行数值计算或输出时,限制小数部分只有两位有效数字,并将多余的位数进行四舍五入或截取。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.08.02

908

3

java基本数据类型
java基本数据类型

java基本数据类型有:1、byte;2、short;3、int;4、long;5、float;6、double;7、char;8、boolean。本专题为大家提供java基本数据类型的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.02

1316

5

java有什么用
java有什么用

java可以开发应用程序、移动应用、Web应用、企业级应用、嵌入式系统等方面。本专题为大家提供java有什么用的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.02

2629

5

java在线网站
java在线网站

Java在线网站是指提供Java编程学习、实践和交流平台的网络服务。近年来,随着Java语言在软件开发领域的广泛应用,越来越多的人对Java编程感兴趣,并希望能够通过在线网站来学习和提高自己的Java编程技能。php中文网给大家带来了相关的视频、教程以及文章,欢迎大家前来学习阅读和下载。

2023.08.03

19951

3

配置java环境变量
配置java环境变量

配置Java环境变量是为了让操作系统能够识别和使用Java的相关命令和功能。本专题为大家提供配置java环境变量相关文章,帮助大家解决问题。

2023.08.03

1175

8

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
dev.java 官方:Learn Java
dev.java 官方:Learn Java

共0课时 | 0人学习

Java JDBC数据库连接官方教程
Java JDBC数据库连接官方教程

共0课时 | 0人学习