Package java.lang.foreign
Provides low-level access to memory and functions outside the Java runtime.
Foreign memory access
The main abstraction introduced to support foreign memory access is MemorySegment
PREVIEW
, which models a contiguous region of memory, residing either inside or outside the Java heap. Memory segments are typically allocated using an Arena
PREVIEW
, which controls the lifetime of the regions of memory backing the segments it allocates. The contents of a memory segment can be described using a memory layout
PREVIEW
, which provides basic operations to query sizes, offsets and alignment constraints. Memory layouts also provide an alternate, more abstract way, to access memory segments using var handlesPREVIEW
, which can be computed using layout paths
. For example, to allocate an off-heap region of memory big enough to hold 10 values of the primitive type int
, and fill it with values ranging from 0
to 9
, we can use the following code:
try (Arena arena = Arena.ofConfined()) {
MemorySegment segment = MemorySegmentarena.allocateNativeallocate(10 * 4, SegmentScope.auto());
for (int i = 0 ; i < 10 ; i++) {
segment.setAtIndex(ValueLayout.JAVA_INT, i, i);
}
}
int
. The native segment is associated with an automatic scopePREVIEW
. This means that the off-heap region of memory backing the segment is managed, automatically, by the garbage collector. allocated using a confined arenaPREVIEW
. As such, the off-heap memory backing the native segment will be released at some unspecified point after
the segment becomes unreachable. This is similar to what happens with direct buffers created via ByteBuffer.allocateDirect(int)
. It is also possible to manage the lifecycle of allocated native segments more directly, as shown in a later section. Inside a loop, we then initialize the contents of the memory segment; note how the access methodPREVIEW
accepts a value layoutPREVIEW
, which specifies the size, alignment constraint, byte order as well as the Java type (int
, in this case) associated with the access operation. More specifically, if we view the memory segment as a set of 10 adjacent slots, s[i]
, where 0 <= i < 10
, where the size of each slot is exactly 4 bytes, the initialization logic above will set each slot so that s[i] = i
, again where 0 <= i < 10
.
Deterministic deallocation
When writing code that manipulates memory segments, especially if backed by memory which resides outside the Java heap, it is often crucial that the resources associated with a memory segment are released when the segment is no longer in use, and in a timely fashion. For this reason, there might be cases where waiting for the garbage collector to determine that a segment is unreachable is not optimal. Clients that operate under these assumptions might want to programmatically release the memory backing a memory segment. This can be done, using theArena
PREVIEW
abstraction, as shown below: try (Arena arena = Arena.openConfined()) {
MemorySegment segment = arena.allocate(10 * 4);
for (int i = 0 ; i < 10 ; i++) {
segment.setAtIndex(ValueLayout.JAVA_INT, i, i);
}
}
Moved out of a heading (level 3) with id safety.Moved to a paragraph.
Safety This API providesMemory segments provide Moved to a paragraph.strong safety guarantees when it comes to memory access. First, when
dereferencingaccessing Moved to a paragraph.a memory segment, the access coordinates are validated (upon access), to make sure that access does not occur at any address which resides Moved to a paragraph.outside Moved to a paragraph. the boundaries of the memory segment used by the access operation. We call this guarantee Moved to a paragraph.spatial safety Moved to a paragraph.; in other words, access to memory segments is bounds-checked, in the same way as array access is, as described in Section Moved out of a link with destination https://docs.oracle.com/javase/specs/jls/se20/html/jls-15.html#jls-15.10.4.Moved to a paragraph.Moved to a link with destination https://docs.oracle.com/javase/specs/jls/se21/html/jls-15.html#jls-15.10.4.15.10.4Moved out of a link with destination https://docs.oracle.com/javase/specs/jls/se20/html/jls-15.html#jls-15.10.4.Moved to a paragraph.Moved to a link with destination https://docs.oracle.com/javase/specs/jls/se21/html/jls-15.html#jls-15.10.4. Moved to a paragraph.of Moved to a paragraph.The Java Language Specification Moved to a paragraph.. Since memory segments created
with an arena can become invalid (see above), segments are Additionally, to prevent a region of memory from being accessed after it has been deallocated (i.e. use-after-free ), a segment is also validated (upon access) to make sure that the scope associated with the segment being accessed is still alivearena from which it has been obtained has not been closed. We call this guarantee temporal safety .
Together, spatial and temporal safety ensure that each memory access operation either succeeds - and accesses a valid location within the region of memory backing the memory segment - or fails.
Foreign function access
The key abstractions introduced to support foreign function access areSymbolLookup
PREVIEW
, FunctionDescriptor
PREVIEW
and Linker
PREVIEW
. The first is used to look up symbols inside libraries; the second is used to model the signature of foreign functions, while the third provides linking capabilities which allows modelling is used to link foreign functions as MethodHandle
instances, so that clients can perform foreign function calls directly in Java, without the need for intermediate layers of C/C++ code (as is the case with the Java Native Interface (JNI)). For example, to compute the length of a string using the C standard library function strlen
on a Linux/x64 platform, we can use the following code:
Linker linker = Linker.nativeLinker();
SymbolLookup stdlib = linker.defaultLookup();
MethodHandle strlen = linker.downcallHandle(
stdlib.find("strlen").getorElseThrow(),
FunctionDescriptor.of(ValueLayout.JAVA_LONG, ValueLayout.ADDRESS)
);
try (Arena arena = Arena.openConfinedofConfined()) {
MemorySegment cString = arena.allocateUtf8String("Hello");
long len = (long)strlen.invokeinvokeExact(cString); // 5
}
strlen
symbol function in the standard C library; a downcall method handle
targeting said symbol function is subsequently obtainedPREVIEW
. To complete the linking successfully, we must provide a FunctionDescriptor
PREVIEW
instance, describing the signature of the strlen
function. From this information, the linker will uniquely determine the sequence of steps which will turn the method handle invocation (here performed using Moved out of a link with destination ../invoke/MethodHandle.html#invoke(java.lang.Object...).Moved to a link with destination ../invoke/MethodHandle.html#invokeExact(java.lang.Object...).MethodHandle.
invokeinvokeExactMoved out of a link with destination ../invoke/MethodHandle.html#invoke(java.lang.Object...).Moved to a link with destination ../invoke/MethodHandle.html#invokeExact(java.lang.Object...).(java.lang.Object...)
) into a foreign function call, according to the rules specified by the ABI of the underlying platform. The Arena
PREVIEW
class also provides many useful methods for interacting with foreign code, such as convertingPREVIEW
Java strings into zero-terminated, UTF-8 strings, as demonstrated in the above example. Moved out of a heading (level 3) with id upcalls.Moved to a heading (level 2) with id restricted.
Upcalls TheLinker
PREVIEW
interface also allows clients to turn an existing method handle (which might point to a Java method) into a memory segment, so that Java code can effectively be passed to other foreign functions. For instance, we can write a method that compares two integer values, as follows: class IntComparator {
static int intCompare(MemorySegment addr1, MemorySegment addr2) {
return addr1.get(ValueLayout.JAVA_INT, 0) -
addr2.get(ValueLayout.JAVA_INT, 0);
}
}
FunctionDescriptor intCompareDescriptor = FunctionDescriptor.of(ValueLayout.JAVA_INT,
ValueLayout.ADDRESS.asUnbounded(),
ValueLayout.ADDRESS.asUnbounded());
MethodHandle intCompareHandle = MethodHandles.lookup().findStatic(IntComparator.class,
"intCompare",
intCompareDescriptor.toMethodType());
FunctionDescriptor
PREVIEW
instance, this time describing the signature of the function pointer we want to create. The descriptor can be used to derivePREVIEW
a method type that can be used to look up the method handle for IntComparator.intCompare
. Now that we have a method handle instance, we can turn it into a fresh function pointer, using the Linker
PREVIEW
interface, as follows:
SegmentScope scope = ...
MemorySegment comparFunc = Linker.nativeLinker().upcallStub(
intCompareHandle, intCompareDescriptor, scope);
);
FunctionDescriptor
PREVIEW
instance created in the previous step is then used to createPREVIEW
a new upcall stub; the layouts in the function descriptors allow the linker to determine the sequence of steps which allow foreign code to call the stub for intCompareHandle
according to the rules specified by the ABI of the underlying platform. The lifecycle of the upcall stub is tied to the scopePREVIEW
provided when the upcall stub is created. This same scope is made available by the MemorySegment
PREVIEW
instance returned by that method. Restricted methods
Some methods in this package are considered restricted . Restricted methods are typically used to bind native foreign data and/or functions to first-class Java API elements which can then be used directly by clients. For instance the restricted methodMoved out of a link with destination MemorySegment.html#ofAddress(long,long,java.lang.foreign.SegmentScope).Moved to a link with destination MemorySegment.html#reinterpret(long).MemorySegment.
ofAddressreinterpretMoved out of a link with destination MemorySegment.html#ofAddress(long,long,java.lang.foreign.SegmentScope).Moved to a link with destination MemorySegment.html#reinterpret(long).(long
, long, SegmentScopeMoved out of a link with destination MemorySegment.html#ofAddress(long,long,java.lang.foreign.SegmentScope).Moved to a link with destination MemorySegment.html#reinterpret(long).)
PREVIEW
can be used to create a fresh segment with the given spatial bounds out of a native addresssame address and temporal bounds, but with the provided size. This can be useful to resize memory segments obtained when interacting with native functions. Binding foreign data and/or functions is generally unsafe and, if done incorrectly, can result in VM crashes, or memory corruption when the bound Java API element is accessed. For instance, in the case of incorrectly resizing a native memory sgement using Moved out of a link with destination MemorySegment.html#ofAddress(long,long,java.lang.foreign.SegmentScope).Moved to a link with destination MemorySegment.html#reinterpret(long).MemorySegment.
ofAddressreinterpretMoved out of a link with destination MemorySegment.html#ofAddress(long,long,java.lang.foreign.SegmentScope).Moved to a link with destination MemorySegment.html#reinterpret(long).(long
, long, SegmentScope)PREVIEW
, if the provided spatial bounds are incorrect, a client of the segment returned by that method might crash the VM, or corrupt memory )
PREVIEW
can lead to a JVM crash, or, worse, lead to silent memory corruption when attempting to access said the resized segment. For these reasons, it is crucial for code that calls a restricted method to never pass arguments that might cause incorrect binding of foreign data and/or functions to a Java API.
Given the potential danger of restricted methods, the Java runtime issues a warning on the standard error stream every time a restricted method is invoked. Such warnings can be disabled by granting access to restricted methods to selected modules. This can be done either via implementation-specific command line options, or programmatically, e.g. by calling ModuleLayer.Controller.enableNativeAccess(java.lang.Module)
PREVIEW
.
For every class in this package, unless specified otherwise, any method arguments of reference type must not be null, and any null argument will elicit a NullPointerException
. This fact is not individually documented for methods of this API.
- API Note:
- Usual memory model guarantees, for example stated in Moved out of a link with destination https://docs.oracle.com/javase/specs/jls/se20/html/jls-6.html#jls-6.6.Moved to a link with destination https://docs.oracle.com/javase/specs/jls/se21/html/jls-6.html#jls-6.6.6.6Moved out of a link with destination https://docs.oracle.com/javase/specs/jls/se20/html/jls-6.html#jls-6.6.Moved to a link with destination https://docs.oracle.com/javase/specs/jls/se21/html/jls-6.html#jls-6.6. and Moved out of a link with destination https://docs.oracle.com/javase/specs/jls/se20/html/jls-10.html#jls-10.4.Moved to a link with destination https://docs.oracle.com/javase/specs/jls/se21/html/jls-10.html#jls-10.4.10.4, do not apply when accessing native memory segments as these segments are backed by off-heap regions of memory.
- Implementation Note:
- In the reference implementation, access to restricted methods can be granted to specific modules using the command line option
--enable-native-access=M1,M2, ... Mn, whereM1,M2,... Mnare module names (for the unnamed module, the special valueALL-UNNAMEDcan be used). If this option is specified, access to restricted methods is only granted to the modules listed by that option. If this option is not specified, access to restricted methods is enabled for all modules, but access to restricted methods will result in runtime warnings. - External Specifications
Types
- ① AddressLayout
- ✗ Arena
- ✗ FunctionDescriptor
- ✗ GroupLayout
- ✗ Linker
- ✗ MemoryLayout
- ✗ MemorySegment
- ✗ PaddingLayout
- ✗ SegmentAllocator
- ① SegmentScope
- ✗ SequenceLayout
- ✗ StructLayout
- ✗ SymbolLookup
- ✗ UnionLayout
- ① VaList
- ✗ ValueLayout
Summary
| Elements | Comments | Descriptions | Total | |||||||
|---|---|---|---|---|---|---|---|---|---|---|
| Added | Changed | Removed | Added | Changed | Removed | Added | Changed | Removed | ||
| java.lang.foreign | 21 | 24 | 46 | 91 | ||||||
| AddressLayout | 1 | 8 | 9 | |||||||
| Arena | 4 | 1 | 3 | 72 | 42 | 38 | 160 | |||
| FunctionDescriptor | 19 | 14 | 12 | 45 | ||||||
| GroupLayout | 2 | 1 | 9 | 10 | 10 | 32 | ||||
| Linker | 3 | 4 | 2 | 191 | 6 | 55 | 261 | |||
| MemoryLayout | 4 | 1 | 6 | 84 | 34 | 74 | 203 | |||
| MemorySegment | 16 | 2 | 11 | 234 | 253 | 210 | 726 | |||
| PaddingLayout | 2 | 1 | 3 | 2 | 4 | 12 | ||||
| SegmentAllocator | 1 | 2 | 17 | 4 | 15 | 39 | ||||
| SegmentScope | 1 | 6 | 7 | |||||||
| SequenceLayout | 2 | 1 | 10 | 11 | 10 | 34 | ||||
| StructLayout | 2 | 1 | 3 | 2 | 5 | 13 | ||||
| SymbolLookup | 3 | 2 | 9 | 9 | 11 | 34 | ||||
| UnionLayout | 2 | 1 | 3 | 2 | 4 | 12 | ||||
| VaList | 2 | 11 | 13 | |||||||
| ValueLayout | 18 | 5 | 10 | 20 | 55 | 28 | 136 | |||
| Total | 60 | 13 | 44 | 703 | 468 | 539 | 1827 | |||