JEP 370:JDK 14的外部内存访问API | Perforce旗下JRebel
随着JDK发布节奏的加快,几乎每周都会有新的JDK增强提案(JEP)发布。本文将聚焦于JEP 370:外部内存访问API(Foreign-Memory Access API,孵化器模块),这是JDK 14中的一项新特性。我们将深入探讨该API的工作原理,并详细介绍其三个核心抽象:内存段(MemorySegment)、内存地址(MemoryAddress)和内存布局(MemoryLayout)。
JEP 370:外部内存访问API(孵化器模块)
JEP 370的核心目标是为Java程序提供访问Java堆之外外部存储器的能力。根据JEP的说明,引入这一API的主要原因包括:
- 支持跨多个进程共享内存。
- 通过将文件映射到内存,实现内存内容的序列化和反序列化。
尽管这一提案的动机明确,但目前的实现尚未提供一种在进程间轻松共享内存的方法。
外部内存访问API是否带来了新功能?
简单来说:没有。许多现有的Java库已经能够访问外部内存,因此JDK 14中新增的外部内存访问API并未直接为这些库增加新功能。然而,该API提供了一种更受支持且更具互操作性的方法,能够在JVM中以更安全的方式处理外部内存,而无需依赖外部库。
在现有的JDK中,类似功能通常通过以下方式实现:
- ByteBuffer API:自Java 1.4以来一直存在。
- JNI(Java Native Interface):需要为每种架构实现本地代码。
- Unsafe API:允许访问任意内存位置,但不受官方支持。
相比之下,外部内存访问API的引入显得尤为必要。
JEP 370与巴拿马项目的关系
JEP 370是巴拿马项目的一部分,该项目旨在提升JVM与非Java API之间的互操作性。通过引入一种可靠且高效的方式与外部内存交互,JEP 370进一步推动了巴拿马项目的目标,同时为未来增强外部函数接口奠定了基础。
外部内存访问API的工作原理
外部内存访问API引入了三个核心抽象:
- MemorySegment:表示一段连续的内存区域。
- MemoryAddress:表示内存段中的具体位置。
- MemoryLayout:以语言中立的方式定义内存段的布局。
由于该API位于孵化器模块中,使用时需要在module-info.java文件中添加jdk.incubator.foreign模块,或者通过--add-modules JVM参数启用。
使用内存段(MemorySegment)
内存段是对连续内存区域的抽象,既可以由堆内存支持,也可以由堆外内存支持。通过工厂方法,可以创建由基元数组、ByteBuffer或文件的内存映射区域支持的内存段,或者分配新的堆外内存段。
为了确保资源的及时释放,MemorySegment实现了AutoCloseable接口,因此可以与try-with-resources一起使用。当内存段被关闭后,再次访问将抛出IllegalStateException。
try (MemorySegment segment = MemorySegment.allocateNative(100)) {
// 使用内存段
}
内存段绑定到创建时的线程。如果需要在其他线程中使用,需要通过acquire()方法获取一个新段。在关闭所有获取的内存段之前,原始内存段无法关闭。
使用内存地址(MemoryAddress)
MemoryAddress表示内存段中的偏移量,通常通过调用segment.baseAddress()方法获取。尽管内存地址是线程安全的,但在多线程环境中使用时,仍需先获取关联的内存段。
try (MemorySegment segment = MemorySegment.allocateNative(100)) {
MemoryAddress address = segment.baseAddress();
}
内存地址通常与VarHandle配合使用,以访问底层数据。例如,以下代码展示了如何以大端字节序写入整数数据:
VarHandle handle = MemoryHandles.varHandle(int.class, ByteOrder.BIG_ENDIAN);
for (int i = 0; i < 32; i++) {
handle.set(segment.baseAddress().addOffset(i * Integer.BYTES), 1 << i);
}
使用内存布局(MemoryLayout)
通过偏移量直接访问内存段可能并不直观。MemoryLayout提供了一种语言中立的方式来描述内存布局,例如声明小端字节序的32位值或本机顺序的64位值。
SequenceLayout layout = MemoryLayout.sequenceLayout(10, MemoryLayouts.JAVA_INT);
更复杂的数据结构也可以通过MemoryLayout描述。例如,一个包含两个整数的点结构可以定义为:
GroupLayout pointLayout = MemoryLayout.structLayout(
MemoryLayouts.JAVA_INT.withName("x"),
MemoryLayouts.JAVA_INT.withName("y")
);
此外,内存布局支持嵌套。例如,一个三角形可以表示为三个点的序列:
SequenceLayout triangleLayout = MemoryLayout.sequenceLayout(3, pointLayout);
使用VarHandle访问单个元素
VarHandle允许通过内存布局访问具体的内存元素。例如,以下代码展示了如何访问三角形中第二个点的x和y坐标:
VarHandle varX = triangleLayout.varHandle(int.class,
MemoryLayout.PathElement.sequenceElement(),
MemoryLayout.PathElement.groupElement("x")
);
VarHandle varY = triangleLayout.varHandle(int.class,
MemoryLayout.PathElement.sequenceElement(),
MemoryLayout.PathElement.groupElement("y")
);
varX.set(triangleSegment.baseAddress(), 1, 10);
varY.set(triangleSegment.baseAddress(), 1, 30);
展望未来
外部内存访问API为描述和访问内存段提供了更有序的工具。未来的改进可能包括支持将记录或内联类直接映射到MemoryLayout,从而简化从内存映射文件读取和写入结构化数据的过程。
总结
JEP 370通过引入外部内存访问API,为Java提供了一种更高效、更安全的方式来与外部内存交互。这不仅提升了JVM的互操作性,也为未来的功能扩展奠定了基础。随着该API的不断完善,Java开发者将能够更轻松地处理复杂的内存操作。
原文链接: https://www.jrebel.com/blog/jep-370-foreign-memory-access-api
热门API
- 1. AI文本生成
- 2. AI图片生成_文生图
- 3. AI图片生成_图生图
- 4. AI图像编辑
- 5. AI视频生成_文生视频
- 6. AI视频生成_图生视频
- 7. AI语音合成_文生语音
- 8. AI文本生成(中国)
最新文章
- 深入解析API网关策略:认证、授权、安全、流量处理与可观测性
- GraphQL API手册:如何构建、测试、使用和记录
- 自助式入职培训服务API:如何让企业管理更上一层楼?
- Python如何调用Jenkins API自动化发布
- 模型压缩四剑客:量化、剪枝、蒸馏、二值化
- 火山引擎如何接入API:从入门到实践的技术指南
- 为什么每个使用 API 的大型企业都需要一个 API 市场来增强其合作伙伴生态系统
- 构建更优质的API:2025年顶级API开发工具推荐 – Strapi
- 外部函数与内存API – Java 22 – 未记录
- FAPI 2.0 深度解析:下一代金融级 API 安全标准与实践指南
- .NET Core 下的 API 网关
- 探索月球的魅力:Moon-API一站式月球数据服务