Java 21中关闭Foreign Memory Segment VarHandle边界检查的方法
问题描述
从Java 17升级至Java 21后,使用java.lang.foreign中的VarHandle时遇到问题:通过VarHandle varhandle = layout.varHandle(path)获取内存段的VarHandle时,该方法会对SequenceLayout执行边界检查并抛出IndexOutOfBoundsException。需要保留Java 17的其他行为,同时关闭该边界检查,且方法需支持任意SequenceLayout。示例代码如下:
var innerLayout = MemoryLayout.structLayout( MemoryLayout.sequenceLayout(5, ValueLayout.JAVA_LONG).withName("a"), ValueLayout.JAVA_INT.withName("b"), ); var layout = MemoryLayout.structLayout( MemoryLayout.sequenceLayout(n, innerLayout).withName("x"), MemoryLayout.sequenceLayout(m, innerLayout).withName("y"), ); var xVarHandle = layout .varHandle(PathElement.groupElement("x"), PathElement.sequenceElement(), PathElement.groupElement("a"), PathElement.sequenceElement()); var yVarHandle = layout .varHandle(PathElement.groupElement("y"), PathElement.sequenceElement(), PathElement.groupElement("a"), PathElement.sequenceElement());
解决方案
Java 21中VarHandle默认对SequenceLayout索引启用边界检查,要兼容Java 17的无校验行为,可通过以下方式关闭检查:
- 在调用
layout.varHandle()时,追加传入VarHandle.AccessMode.UNCHECKED访问模式参数,该参数会让VarHandle跳过索引边界校验,且支持任意嵌套或顶层的SequenceLayout。
修改后的示例代码:
var innerLayout = MemoryLayout.structLayout( MemoryLayout.sequenceLayout(5, ValueLayout.JAVA_LONG).withName("a"), ValueLayout.JAVA_INT.withName("b"), ); var layout = MemoryLayout.structLayout( MemoryLayout.sequenceLayout(n, innerLayout).withName("x"), MemoryLayout.sequenceLayout(m, innerLayout).withName("y"), ); // 传入UNCHECKED模式关闭边界检查 var xVarHandle = layout .varHandle( PathElement.groupElement("x"), PathElement.sequenceElement(), PathElement.groupElement("a"), PathElement.sequenceElement(), VarHandle.AccessMode.UNCHECKED ); var yVarHandle = layout .varHandle( PathElement.groupElement("y"), PathElement.sequenceElement(), PathElement.groupElement("a"), PathElement.sequenceElement(), VarHandle.AccessMode.UNCHECKED );
注意事项
UNCHECKED模式是Java官方提供的标准兼容方式,不会影响Java 17的其他行为。- 使用该模式后,需自行确保索引操作的合法性,避免出现内存越界访问风险。
内容的提问来源于stack exchange,提问作者BonBun
相关产品推荐
相关产品推荐

