JVM常用概念之信任非静态final字段

server/2025/3/20 3:41:25/

问题

JVM可以信任非静态的final字段吗?

基础知识

编译器通常信任static final字段,因为已知该值不依赖于特定对象,并且已知它不会改变。那对于静态常量实例的final字段也使如此吗?

class M {final int x;M(int x) { this.x = x; }
}static final M KNOWN_M = new M(1337);void work() {// We know exactly the slot that holds the variable, can we just// inline the value 1337 here?return KNOWN_M.x;
}

Java 言规范允许不看到这样的更新,因为字段是final 。不幸的是,真正的框架设法依赖于更强大的行为:字段更新将被看到。正在进行的实验积极优化这些情况,并在实际写入发生时取消优化。当前状态是一些内部类是隐式信任的,下面是OpenJDK的源码:

static bool trust_final_non_static_fields(ciInstanceKlass* holder) {if (holder == NULL)return false;if (holder->name() == ciSymbol::java_lang_System())// Never trust strangely unstable finals:  System.out, etc.return false;// Even if general trusting is disabled, trust system-built closures in these packages.if (holder->is_in_package("java/lang/invoke") || holder->is_in_package("sun/invoke"))return true;// Trust VM anonymous classes. They are private API (sun.misc.Unsafe) and can't be serialized,// so there is no hacking of finals going on with them.if (holder->is_anonymous())return true;// Trust final fields in all boxed classesif (holder->is_box_klass())return true;// Trust final fields in Stringif (holder->name() == ciSymbol::java_lang_String())return true;// Trust Atomic*FieldUpdaters: they are very important for performance, and make up one// more reason not to use Unsafe, if their final fields are trusted. See more in JDK-8140483.if (holder->name() == ciSymbol::java_util_concurrent_atomic_AtomicIntegerFieldUpdater_Impl() ||holder->name() == ciSymbol::java_util_concurrent_atomic_AtomicLongFieldUpdater_CASUpdater() ||holder->name() == ciSymbol::java_util_concurrent_atomic_AtomicLongFieldUpdater_LockedUpdater() ||holder->name() == ciSymbol::java_util_concurrent_atomic_AtomicReferenceFieldUpdater_Impl()) {return true;}return TrustFinalNonStaticFields;
}

并且,只有在提供实验性的 -XX:+TrustFinalNonStaticFields运行参数时,常规的final字段才会受到信任。

实验

源码

@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Fork(3)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@State(Scope.Benchmark)
public class TrustFinalFields {static final T t_static_final;static       T t_static;final T t_inst_final;T t_inst;static {t_static_final = new T(1000);t_static = new T(1000);}{t_inst_final = new T(1000);t_inst = new T(1000);}static class T {final int x;public T(int x) {this.x = x;}}@Benchmark public int _static_final() { return 1000 / t_static_final.x; }@Benchmark public int _static()       { return 1000 / t_static.x;       }@Benchmark public int _inst_final()   { return 1000 / t_inst_final.x;   }@Benchmark public int _inst()         { return 1000 / t_inst.x;         }}

运行结果

Benchmark                       Mode  Cnt  Score   Error  Units
TrustFinalFields._inst          avgt   15  4.316 ± 0.003  ns/op
TrustFinalFields._inst_final    avgt   15  4.317 ± 0.002  ns/op
TrustFinalFields._static        avgt   15  4.282 ± 0.011  ns/op
TrustFinalFields._static_final  avgt   15  4.202 ± 0.002  ns/op

汇编代码如下:

0.02%   ↗  movabs $0x782b67520,%r10   ; {oop(a 'org/openjdk/TrustFinalFields$T';)}│  mov    0x10(%r10),%r10d    ; get field $x...
0.19%   │  cltd
0.02%   │  idiv   %r10d               ; idiv│  ...
0.16%   │  test   %r11d,%r11d         ; check and run @Benchmark again╰  je     BACK

对象本身被信任位于堆中的给定位置( $0x782b67520 ),但我们不信任该字段!使用 -XX:+TrustFinalNonStaticFields 运行相同操作会产生以下结果:

Benchmark                       Mode  Cnt  Score    Error  Units
TrustFinalFields._inst          avgt   15  4.318 ±  0.001  ns/op
TrustFinalFields._inst_final    avgt   15  4.317 ±  0.003  ns/op
TrustFinalFields._static        avgt   15  4.290 ±  0.002  ns/op
TrustFinalFields._static_final  avgt   15  1.901 ±  0.001  ns/op  # <--- !!!

从上述的执行结果可以看出,这里final一个字段被折叠了,如 perfasm 输出所示:

3.04%   ↗  mov    %r10,(%rsp)│  mov    0x38(%rsp),%rsi
8.26%   │  mov    $0x1,%edx           ; <--- constant folded to 1...
0.04%   │  test   %r11d,%r11d         ; check and run @Benchmark again╰  je     BACK

总结

信任实例最终字段需要了解我们正在操作的对象。因此,至少对于已知的系统类而言。通过这些最终字段进行常量折叠是MethodHandle -s、 VarHandle -s`、 Atomic*FieldUpdaters和核心库中其他高性能实现的性能基础。应用程序可能会尝试使用实验性的 VM 选项,但行为不当的应用程序可能造成的破坏可能会得不偿失。


http://www.ppmy.cn/server/176411.html

相关文章

网络安全运维应急响应与溯源分析实战案例

在日常运维过程中&#xff0c;网络安全事件时有发生&#xff0c;快速响应和精准溯源是保障业务稳定运行的关键。本文将通过一个实际案例&#xff0c;详细解析从发现问题到溯源定位&#xff0c;再到最终解决的完整流程。 目录 一、事件背景 二、事件发现 1. 监控告警触发 2.…

Redis的IO多路复用机制:高效的网络通信设计

在高并发、高性能的应用中&#xff0c;如何有效地管理和处理大量的客户端请求是一个至关重要的问题。Redis作为一个高性能的内存数据存储系统&#xff0c;面对大量并发客户端请求时&#xff0c;需要具备良好的网络通信能力。在Redis的设计中&#xff0c;IO多路复用机制是其核心…

N皇后问题——dfs解法(回溯+减枝+深搜)

一.题目 这是一道很经典的题&#xff0c;首先分析一下题目&#xff0c;就是在棋盘上下棋&#xff0c;但是同一行&#xff0c;同一列&#xff0c;对角线上不能有棋子&#xff0c;否则无法落子&#xff0c;那这些信息也就是约束条件&#xff0c;模拟这些信息就是减枝函数的内容 …

【数据分享】2000—2024年我国省市县三级逐年归一化植被指数(NDVI)数据(年最大值/Shp/Excel格式)

之前我们分享过2000-2024年我国逐年的归一化植被指数&#xff08;NDVI&#xff09;栅格数据&#xff0c;该逐年数据是取的当年月归一化植被指数&#xff08;NDVI&#xff09;的年最大值。&#xff08;可查看之前的文章获悉详情&#xff09;&#xff01;该数据来源于NASA定期发布…

【第九节】windows sdk编程:通用控件的使用

目录 引言 一、通用控件简介 二、 WM_NOTIFY 消息 三、通用控件的使用 3.1 进度条 3.2 滑块 3.3 ListControl 引言 通用控件是Windows操作系统扩展的一组功能丰富的界面元素&#xff0c;广泛应用于各类应用程序中。它们不仅简化了用户界面的开发&#xff0c;还提供了强大…

HiPixel开源AI驱动的图像超分辨率的原生macOS 应用程序,使用 SwiftUI 构建并利用 Upscayl 强大的 AI 模型

一、软件介绍 文末提供程序和源码下载 HiPixel是一个开源程序基于SwiftUI构建的macOS原生应用程序&#xff0c;用于AI驱动的图像超分辨率&#xff0c;并利用Upscayl的强大AI模型。 二、软件特征 具有 SwiftUI 界面的原生 macOS 应用程序使用 AI 模型进行高质量图像放大通过 G…

HW基本的sql流量分析和wireshark 的基本使用

前言 HW初级的主要任务就是看监控&#xff08;流量&#xff09; 这个时候就需要我们 了解各种漏洞流量数据包的信息 还有就是我们守护的是内网环境 所以很多的攻击都是 sql注入 和 webshell上传 &#xff08;我们不管对面是怎么拿到网站的最高权限的 我们是需要指出它是…

Flume详解——介绍、部署与使用

1. Flume 简介 Apache Flume 是一个专门用于高效地 收集、聚合、传输 大量日志数据的 分布式、可靠 的系统。它特别擅长将数据从各种数据源&#xff08;如日志文件、消息队列等&#xff09;传输到 HDFS、HBase、Kafka 等大数据存储系统。 特点&#xff1a; 可扩展&#xff1…