不写 JNI 也能调 C?Java 的 Foreign Function & Memory API 怎么描述 C 结构体?越界、关闭后访问会怎样?JDK 21 的预览版和 JDK 27 的正式版又有哪些区别?这篇用真的 C 库把它们跑一遍。
1 getpid:27372(Java 里 ProcessHandle.current().pid()=27372)
2 strlen("Hello, FFM!")=11;往返读回 Hello, FFM!;段大小 12(含结尾的 0)
3 qsort 用 Java 比较器排序:[1, 3, 5, 7, 9]
4 C 的 sizeof(Rec)=32,offsetof tag/id/big/d/name=0/4/8/16/24,对齐 8
Java 的 REC.byteSize()=32,offset id/big/d/name=4/8/16/24,byteAlignment 8
5 C 填充的结构体在 Java 里读出:tag=7,id=42,big=42000000294,d=10.5,name=rec
6 C 的 sum_array 对 Java 分配的 int[10]:55
7 错误:
越界读(offset 14 读 int,段 16 字节):IndexOutOfBoundsException: Out of bound access on segment MemorySegment{ heapBase: Optional.empty address:523132688992 limit: 16 }; new offset = 14; new length = 4
未对齐读(offset 4 读 long):IllegalArgumentException: Misaligned access at address: 523132688996
负偏移:IndexOutOfBoundsException: Out of bound access on segment MemorySegment{ heapBase: Optional.empty address:523132688992 limit: 16 }; new offset = -4; new length = 4
只读段写入:UnsupportedOperationException: Attempt to write a read-only segment
Arena 关闭之后访问:IllegalStateException: Already closed
重复关闭 Arena:IllegalStateException: Already closed
confined Arena 的段被其它线程访问:WrongThreadException: Attempted access outside owning thread
shared Arena 的段在其它线程写入后读到:5
ofAuto Arena(由 GC 回收):读到 3
ofAuto 不能手动 close:UnsupportedOperationException: Attempted to close a non-closeable session
8 getpid 下行调用:2000 万次共 112 ms,平均 5.6 ns/次(x=true) 编译失败: <jtmp>/j163a/Main.java:4: error: ValueLayout is a preview API and is disabled by default.
import static java.lang.foreign.ValueLayout.*;
^
(use --enable-preview to enable preview APIs) 1 getpid:27378(Java 里 ProcessHandle.current().pid()=27378)
2 strlen("Hello, FFM!")=11;往返读回 Hello, FFM!;段大小 12(含结尾的 0)
3 qsort 用 Java 比较器排序:[1, 3, 5, 7, 9]
4 C 的 sizeof(Rec)=32,offsetof tag/id/big/d/name=0/4/8/16/24,对齐 8
Java 的 REC.byteSize()=32,offset id/big/d/name=4/8/16/24,byteAlignment 8
5 C 填充的结构体在 Java 里读出:tag=7,id=42,big=42000000294,d=10.5,name=rec
6 C 的 sum_array 对 Java 分配的 int[10]:55
7 错误:
越界读(offset 14 读 int,段 16 字节):IndexOutOfBoundsException: Out of bound access on segment MemorySegment{ kind: native, address: 0x77ea101260, byteSize: 16 }; attempting to access an element of length 4 at offs
未对齐读(offset 4 读 long):IllegalArgumentException: Target offset 4 is incompatible with alignment constraint 8 (of j8) for segment MemorySegment{ kind: native, address: 0x77ea101260, byteSize: 16 }
负偏移:IndexOutOfBoundsException: Out of bound access on segment MemorySegment{ kind: native, address: 0x77ea101260, byteSize: 16 }; attempting to access an element of length 4 at offs
只读段写入:IllegalArgumentException: Attempt to write a read-only segment
Arena 关闭之后访问:IllegalStateException: Already closed
重复关闭 Arena:IllegalStateException: Already closed
confined Arena 的段被其它线程访问:WrongThreadException: Attempted access outside owning thread
shared Arena 的段在其它线程写入后读到:5
ofAuto Arena(由 GC 回收):读到 3
ofAuto 不能手动 close:UnsupportedOperationException: Attempted to close a non-closeable session
8 getpid 下行调用:2000 万次共 147 ms,平均 7.4 ns/次(x=true)
WARNING: A restricted method in java.lang.foreign.Linker has been called
WARNING: java.lang.foreign.Linker::downcallHandle has been called by Main in an unnamed module (file:<jtmp>/j163a/out/)
WARNING: Use --enable-native-access=ALL-UNNAMED to avoid a warning for callers in this module
WARNING: Restricted methods will be blocked in a future release unless native access is enabled 1 getpid:27382(Java 里 ProcessHandle.current().pid()=27382)
2 strlen("Hello, FFM!")=11;往返读回 Hello, FFM!;段大小 12(含结尾的 0)
3 qsort 用 Java 比较器排序:[1, 3, 5, 7, 9]
4 C 的 sizeof(Rec)=32,offsetof tag/id/big/d/name=0/4/8/16/24,对齐 8
Java 的 REC.byteSize()=32,offset id/big/d/name=4/8/16/24,byteAlignment 8
5 C 填充的结构体在 Java 里读出:tag=7,id=42,big=42000000294,d=10.5,name=rec
6 C 的 sum_array 对 Java 分配的 int[10]:55
7 错误:
越界读(offset 14 读 int,段 16 字节):IndexOutOfBoundsException: Out of bound access on segment MemorySegment{ kind: native, address: 0x7a1ee19440, byteSize: 16 }; attempting to access an element of length 4 at offs
未对齐读(offset 4 读 long):IllegalArgumentException: Target offset 4 is incompatible with alignment constraint 8 (of j8) for segment MemorySegment{ kind: native, address: 0x7a1ee19440, byteSize: 16 }
负偏移:IndexOutOfBoundsException: Out of bound access on segment MemorySegment{ kind: native, address: 0x7a1ee19440, byteSize: 16 }; attempting to access an element of length 4 at offs
只读段写入:IllegalArgumentException: Attempt to write a read-only segment
Arena 关闭之后访问:IllegalStateException: Already closed
重复关闭 Arena:IllegalStateException: Already closed
confined Arena 的段被其它线程访问:WrongThreadException: Attempted access outside owning thread
shared Arena 的段在其它线程写入后读到:5
ofAuto Arena(由 GC 回收):读到 3
ofAuto 不能手动 close:UnsupportedOperationException: Attempted to close a non-closeable session
8 getpid 下行调用:2000 万次共 145 ms,平均 7.3 ns/次(x=true)