Abd*_*azi 4 java project-panama java-21 java-ffm
我正在尝试测试 Java 21 的外部函数和内存功能。这是我的代码:
\npublic static void main(String[] args) {\n // 1. Find foreign function on the C library path\n Linker linker = Linker.nativeLinker();\n SymbolLookup stdlib = linker.defaultLookup();\n MethodHandle radixsort = linker.downcallHandle(stdlib.find("radixsort").orElseThrow(), FunctionDescriptor.ofVoid(ValueLayout.ADDRESS, ValueLayout.JAVA_INT, ValueLayout.ADDRESS, ValueLayout.JAVA_CHAR));\n // 2. Allocate on-heap memory to store four strings\n String[] javaStrings = {"mouse", "cat", "dog", "car"};\n\n // 3. Use try-with-resources to manage the lifetime of off-heap memory\n try (Arena offHeap = Arena.ofConfined()) {\n // 4. Allocate a region of off-heap memory to store four pointers\n MemorySegment pointers = offHeap.allocateArray(ValueLayout.ADDRESS, javaStrings.length);\n // 5. Copy the strings from on-heap to off-heap\n for (int i = 0; i < javaStrings.length; i++) {\n MemorySegment cString = offHeap.allocateUtf8String(javaStrings[i]);\n pointers.setAtIndex(ValueLayout.ADDRESS, i, cString);\n assert cString.getUtf8String(0).length() > 0;\n }\n // 6. Sort the off-heap data by calling the foreign function\n radixsort.invoke(pointers, javaStrings.length, MemorySegment.NULL, '\\0');\n // 7. Copy the (reordered) strings from off-heap to on-heap\n for (int i = 0; i < javaStrings.length; i++) {\n MemorySegment cString = pointers.getAtIndex(ValueLayout.ADDRESS, i);\n javaStrings[i] = cString.getUtf8String(0);\n }\n } // 8. All off-heap memory is deallocated here\n catch (Throwable e) {\n throw new RuntimeException(e);\n }\n assert Arrays.equals(javaStrings, new String[]{"car", "c\xe2\x88\x9eat", "dog", "mouse"}); // true\n }\nRun Code Online (Sandbox Code Playgroud)\n但我遇到了这个错误:
\nException in thread "main" java.lang.RuntimeException: java.lang.IndexOutOfBoundsException: Out of bound access on segment MemorySegment{ heapBase: Optional.empty address:105553153094096 limit: 0 }; new offset = 0; new length = 1
在线:
\njavaStrings\\[i\\] = cString.getUtf8String(0);\n似乎MemorySegment cString = pointers.getAtIndex(ValueLayout.ADDRESS, i);返回一个 byteSize = 0 的 MemorySegment
当我cString.getUtf8String(0);在原始 cString 上使用时,我没有遇到错误。
看来pointers.setAtIndex并pointers.getAtIndex没有保留MemorySegment的byteSize。?
看来pointers.setAtIndex和pointers.getAtIndex不保留MemorySegment byteSize。?
对,那是正确的。该地址作为普通内存地址存储到堆外内存中。尺寸已下降。因此,当从堆外内存读回地址时,创建的内存段的大小为 0。
MemorySegment 的 javadoc中也对此进行了解释:
当与外部函数交互时,这些函数通常会分配一个内存区域并返回指向该区域的指针。使用内存段对内存区域进行建模具有挑战性,因为 Java 运行时无法了解该区域的大小。只有存储在指针中的区域起始地址可用。
...
MemorySegment API 使用零长度内存段来表示:
- 从外部函数返回的指针;
- 由外部函数传递给上行调用存根的指针;和
- 从内存段读取的指针(更多内容见下文)。
您的用例是这三个用例中的后者。
您必须MemorySegment::reinterpret显式地调整段的大小。由于对于 C 字符串,实际大小未知(由空终止符指示),因此您可以调整段大小以使其可Long.MAX_VALUE访问:
// 7. Copy the (reordered) strings from off-heap to on-heap
for (int i = 0; i < javaStrings.length; i++) {
MemorySegment cString = pointers.getAtIndex(ValueLayout.ADDRESS, i);
cString = cString.reinterpret(Long.MAX_VALUE); // <----
javaStrings[i] = cString.getUtf8String(0);
}
Run Code Online (Sandbox Code Playgroud)
或者,您可以创建一个AddressLayout具有所需大小的目标布局,以避免单独调用reinterpret:
AddressLayout UNBOUNDED_POINTER = ValueLayout.ADDRESS
.withTargetLayout(MemoryLayout.sequenceLayout(Long.MAX_VALUE, ValueLayout.JAVA_BYTE));
Run Code Online (Sandbox Code Playgroud)
然后用它来取消引用:
// 7. Copy the (reordered) strings from off-heap to on-heap
for (int i = 0; i < javaStrings.length; i++) {
MemorySegment cString = pointers.getAtIndex(UNBOUNDED_POINTER, i);
// no reinterpret needed
javaStrings[i] = cString.getUtf8String(0);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
238 次 |
| 最近记录: |