Java 22升级至23时堆外内存访问越界问题求助
Java 23堆外内存VarHandle访问触发IndexOutOfBoundsException问题
将Java版本从22升级至23后,涉及堆外内存操作的业务代码出现异常,具体情况如下:
核心异常代码
val intVh = MemoryLayout .sequenceLayout( Long.MaxValue / ValueLayout.JAVA_INT.byteSize(), ValueLayout.JAVA_INT, ) .varHandle(PathElement.sequenceElement()) @IntrinsicCandidate @inline def set[R <: Global](mem: Memory[L, R], value: Int, x1: Int)( implicit region: Region[R], ): Unit = { intVh.set(mem.asJava, vh.offset0 + vh.step1 * x1 + vh.offset1, 0L, value) }
异常信息
Java 22环境测试正常,但升级到23后触发IndexOutOfBoundsException:
Assertion failed: Exception in thread "zio-fiber-71,58,53" java.lang.IndexOutOfBoundsException: Out of bound access on segment MemorySegment{ address: 0x60000228f000, byteSize: 40 }; new offset = 0; new length = 9223372036854775804 at java.base/jdk.internal.foreign.AbstractMemorySegmentImpl.outOfBoundException(AbstractMemorySegmentImpl.java:439) ...(省略部分栈帧)
修复后正常代码
修改为直接调用MemorySegment的set方法后,Java 22和23环境下均正常运行:
mem .asJava .set( ValueLayout.JAVA_INT, vh.offset0 + vh.step1 * x1 + vh.offset1, value, )
补充信息
mem.asJava为MemorySegment实例- 实际访问的偏移量范围为0到10
- 代码中传入
0L是之前为规避OpenJ9的某个问题而添加的写法
问题分析
Java 23对堆外内存API的边界校验逻辑做了关键变更:
- 原代码创建的
sequenceLayout长度为Long.MaxValue / 4(约2.3e18),远大于实际使用的MemorySegment(仅40字节) - Java 22中,通过该布局生成的
VarHandle访问内存时,未严格校验布局总长度与内存段实际长度的匹配关系 - Java 23开始,
VarHandle会结合关联的布局总长度做合法性校验——当内存段长度远小于布局长度时,直接判定为越界访问 MemorySegment.set方法仅基于内存段自身的边界做校验,只要偏移量在内存段范围内即可正常执行,因此不受布局长度影响
内容的提问来源于stack exchange,提问作者Person Person
相关产品推荐
相关产品推荐

