AddressLayout, GroupLayout, PaddingLayout, SequenceLayout, StructLayout, UnionLayout, ValueLayout, ValueLayout.OfBoolean, ValueLayout.OfByte, ValueLayout.OfChar, ValueLayout.OfDouble, ValueLayout.OfFloat, ValueLayout.OfInt, ValueLayout.OfLong, ValueLayout.OfShortpublic sealed interface MemoryLayout permits SequenceLayout, GroupLayout, PaddingLayout, ValueLayout
There are two leaves in the layout hierarchy, value layouts, which are used to represent values of given size and kind and padding layouts which are used, as the name suggests, to represent a portion of a memory segment whose contents should be ignored, and which are primarily present for alignment reasons. Some common value layout constants, such as ValueLayout.JAVA_INT and ValueLayout.JAVA_FLOAT_UNALIGNED are defined in the ValueLayout class. A special kind of value layout, namely an address layout, is used to model values that denote the address of a region of memory.
More complex layouts can be derived from simpler ones: a sequence layout denotes a homogeneous repetition of zero or more occurrences of an element layout; a group layout denotes a heterogeneous aggregation of zero or more member layouts. Group layouts come in two flavors: struct layouts, where member layouts are laid out one after the other, and union layouts where member layouts are laid out at the same starting offset.
Layouts can be optionally associated with a name. A layout name can be referred to when constructing layout paths.
Consider the following struct declaration in C:
typedef struct {
char kind;
int value;
} TaggedValues[5];
SequenceLayout TAGGED_VALUES = MemoryLayout.sequenceLayout(5,
MemoryLayout.structLayout(
ValueLayout.JAVA_BYTE.withName("kind"),
MemoryLayout.paddingLayout(3),
ValueLayout.JAVA_INT.withName("value")
)
).withName("TaggedValues");
ValueLayout.JAVA_INT has carrier int, and size of 4 bytes;ValueLayout.ADDRESS has a size of 8 bytes on a 64-bit platform;Furthermore, all layouts have a natural alignment (expressed in bytes) which is defined as follows:
withByteAlignment(long)), which can be useful to describe layouts with weaker or stronger alignment constraints. Layout paths can be used to:
For instance, given the taggedValues sequence layout constructed above, we can obtain the offset, in bytes, of the member layout named value in the first sequence element, as follows:
long valueOffset = TAGGED_VALUES.byteOffset(PathElement.sequenceElement(0),
PathElement.groupElement("value")); // yields 4
value, as follows: MemoryLayout value = TAGGED_VALUES.select(PathElement.sequenceElement(),
PathElement.groupElement("value"));
MemoryLayout.PathElement.sequenceElement(), MemoryLayout.PathElement.sequenceElement(long, long) select an unspecified element in a sequence layout. A var handle derived from a layout path containing one or more open path element features additional coordinates of type long, which can be used by clients to bind the open elements in the path: VarHandle valueHandle = TAGGED_VALUES.varHandle(PathElement.sequenceElement(),
PathElement.groupElement("value"));
MemorySegment taggedValues = ...
// reads the "value" field of the third struct in the array (taggedValues[2].value)
int val = (int) valueHandle.get(taggedValues,
0L, // base offset
2L); // sequence index
Open path elements also affect the creation of offset-computing method handles. Each open path element becomes an additional long parameter in the obtained method handle. This parameter can be used to specify the index of the sequence element whose offset is to be computed:
MethodHandle offsetHandle = TAGGED_VALUES.byteOffsetHandle(PathElement.sequenceElement(),
PathElement.groupElement("kind"));
long offset1 = (long) offsetHandle.invokeExact(0L, 1L); // 0 + (1 * 8) = 8
long offset2 = (long) offsetHandle.invokeExact(0L, 2L); // 0 + (2 * 8) = 16
StructLayout RECTANGLE = MemoryLayout.structLayout(
ValueLayout.ADDRESS.withTargetLayout(
MemoryLayout.sequenceLayout(4,
MemoryLayout.structLayout(
ValueLayout.JAVA_INT.withName("x"),
ValueLayout.JAVA_INT.withName("y")
).withName("point")
)
).withName("points")
);
points, an address layout whose target layout is a sequence layout of four struct layouts. Each struct layout describes a two-dimensional point, and is defined as a pair or ValueLayout.JAVA_INT coordinates, with names x and y, respectively. With dereference path elements, we can obtain a var handle that accesses the y coordinate of one of the point in the rectangle, as follows:
VarHandle rectPointYs = RECTANGLE.varHandle(
PathElement.groupElement("points"),
PathElement.dereferenceElement(),
PathElement.sequenceElement(),
PathElement.groupElement("y")
);
MemorySegment rect = ...
// dereferences the third point struct in the "points" array, and reads its "y" coordinate (rect.points[2]->y)
int rect_y_2 = (int) rectPointYs.get(rect,
0L, // base offset
2L); // sequence index
C_0, also called the initial layout. Each path element in a layout path can be thought of as a function that updates the current layout C_i-1 to some other layout C_i. That is, for each path element E1, E2, ... En, in a layout path P, we compute C_i = f_i(C_i-1), where f_i is the selection function associated with the path element under consideration, denoted as E_i. The final layout C_i is also called the selected layout. A layout path P is considered well-formed for an initial layout C_0 if all its path elements E1, E2, ... En are well-formed for their corresponding input layouts C_0, C_1, ... C_n-1. A path element E is considered well-formed for a layout L if any of the following is true:
L is a sequence layout and E is a sequence path element (one of MemoryLayout.PathElement.sequenceElement(long), MemoryLayout.PathElement.sequenceElement(long, long) or MemoryLayout.PathElement.sequenceElement()). Moreover, if E contains one or more sequence indices, such indices have to be compatible with the sequence layout's element count;L is a group layout and E is a group path element (one of MemoryLayout.PathElement.groupElement(String) or MemoryLayout.PathElement.groupElement(long)). Moreover, the group path element must refer to a valid member layout in L, either by name, or index;L is an address layout and E is a dereference path element. Moreover, L must define some target layout.P that is not well-formed for an initial layout C_0 will result in an IllegalArgumentException. varHandle(PathElement...) or ValueLayout.varHandle() features certain access characteristics, which are derived from the selected layout L: T, derived from L.carrier()
A, derived from L.byteAlignment()
S, derived from L.byteSize()
A is compatible with the access size S, that is if A >= S. An aligned var handle is guaranteed to support the following access modes: T. Access modes get and set for long, double and MemorySegment are supported but have no atomicity guarantee, as described in Section 17.7 of The Java Language Specification. int, long, float, double and MemorySegment. (Future major platform releases of the JDK may support additional types for certain currently unsupported access modes.) int, long and MemorySegment. (Future major platform releases of the JDK may support additional numeric types for certain currently unsupported access modes.) int, long and MemorySegment. (Future major platform releases of the JDK may support additional numeric types for certain currently unsupported access modes.) T is float, double or MemorySegment then atomic update access modes compare values using their bitwise representation (see Float.floatToRawIntBits(float), Double.doubleToRawLongBits(double) and MemorySegment.address(), respectively). Alternatively, a var handle is unaligned if its alignment constraint A is incompatible with the access size S, that is, if A < S. An unaligned var handle only supports the get and set access modes. All other access modes will result in UnsupportedOperationException being thrown. Moreover, while supported, access modes get and set might lead to word tearing.
typedef struct {
int x;
int y;
} Point;
x and y respectively). Now consider the following snippet of C code: int size = ...
Point *points = (Point*)malloc(sizeof(Point) * size);
for (int i = 0 ; i < size ; i++) {
... points[i].x ...
}
points). Crucially, the size of the array is dynamically bound to the value of the size variable. Inside the loop, the x coordinate of all the points in the array is accessed. To model this code in Java, let's start by defining a layout for the Point struct, as follows:
StructLayout POINT = MemoryLayout.structLayout(
ValueLayout.JAVA_INT.withName("x"),
ValueLayout.JAVA_INT.withName("y")
);
VarHandle POINT_ARR_X = POINT.arrayElementVarHandle(PathElement.groupElement("x"));
int size = ...
MemorySegment points = ...
for (int i = 0 ; i < size ; i++) {
... POINT_ARR_X.get(points, 0L, (long)i) ...
}
x of subsequent point in the array is accessed using the POINT_ARR_X var handle, which is obtained using the arrayElementVarHandle(PathElement...) method. This var handle features two long coordinates: the first is a base offset (set to 0L), while the second is a logical index that can be used to stride over all the elements of the point array. The base offset coordinate allows clients to express complex access operations, by injecting additional offset computation into the var handle (we will see an example of that below). In cases where the base offset is constant (as in the previous example) clients can, if desired, drop the base offset parameter and make the access expression simpler. This is achieved using the MethodHandles.insertCoordinates(VarHandle, int, Object...) var handle adapter.
typedef struct {
int size;
Point points[];
} Polygon;
points array is left unspecified in the C declaration, using a Flexible Array Member (a feature standardized in C99). Again, clients can perform structured access to elements in the nested variable-length array using the arrayElementVarHandle(PathElement...) method, as demonstrated below:
StructLayout POLYGON = MemoryLayout.structLayout(
ValueLayout.JAVA_INT.withName("size"),
MemoryLayout.sequenceLayout(0, POINT).withName("points")
);
VarHandle POLYGON_SIZE = POLYGON.varHandle(0, PathElement.groupElement("size"));
long POINTS_OFFSET = POLYGON.byteOffset(PathElement.groupElement("points"));
POLYGON layout contains a sequence layout of size zero. The element layout of the sequence layout is the POINT layout, shown previously. The polygon layout is used to obtain a var handle that provides access to the polygon size, as well as an offset (POINTS_OFFSET) to the start of the variable-length points array. The x coordinates of all the points in a polygon can then be accessed as follows:
MemorySegment polygon = ...
int size = POLYGON_SIZE.get(polygon, 0L);
for (int i = 0 ; i < size ; i++) {
... POINT_ARR_X.get(polygon, POINTS_OFFSET, (long)i) ...
}
POLYGON_SIZE var handle. Then, in a loop, we read the x coordinates of all the points in the polygon. This is done by providing a custom offset (namely, POINTS_OFFSET) to the offset coordinate of the POINT_ARR_X var handle. As before, the loop induction variable i is passed as the index of the POINT_ARR_X var handle, to stride over all the elements of the variable-length array.| Modifier and Type | Interface | Description |
|---|---|---|
static interface |
MemoryLayout.PathElement |
An element in a layout path. |
| Modifier and Type | Method | Description |
|---|---|---|
VarHandle |
arrayElementVarHandle |
Creates a var handle that accesses adjacent elements in a memory segment at offsets selected by the given layout path, where the accessed elements have this layout, and where the initial layout in the path is this layout. |
long |
byteAlignment() |
Returns the alignment constraint associated with this layout, expressed in bytes. |
long |
byteOffset |
Computes the offset, in bytes, of the layout selected by the given layout path, where the initial layout in the path is this layout. |
MethodHandle |
byteOffsetHandle |
Creates a method handle that computes the offset, in bytes, of the layout selected by the given layout path, where the initial layout in the path is this layout. |
long |
byteSize() |
Returns the layout size, in bytes. |
boolean |
equals |
Compares the specified object with this layout for equality. |
int |
hashCode() |
Returns the hash code value for this layout. |
Optional |
name() |
Returns the name (if any) associated with this layout. |
static PaddingLayout |
paddingLayout |
Creates a padding layout with the given byte size. |
long |
scale |
Returns offset + (byteSize() * index). |
MethodHandle |
scaleHandle() |
Returns a method handle that can be used to invoke scale(long, long) on this layout. |
MemoryLayout |
select |
Returns the layout selected from the provided path, where the initial layout in the path is this layout. |
static SequenceLayout |
sequenceLayout |
Creates a sequence layout with the given element layout and element count. |
MethodHandle |
sliceHandle |
Creates a method handle which, given a memory segment, returns a slice corresponding to the layout selected by the given layout path, where the initial layout in the path is this layout. |
static StructLayout |
structLayout |
Creates a struct layout with the given member layouts. |
String |
toString() |
Returns the string representation of this layout. |
static UnionLayout |
unionLayout |
Creates a union layout with the given member layouts. |
VarHandle |
varHandle |
Creates a var handle that accesses a memory segment at the offset selected by the given layout path, where the initial layout in the path is this layout. |
MemoryLayout |
withByteAlignment |
Returns a memory layout with the same characteristics as this layout, but with the given alignment constraint (in bytes). |
MemoryLayout |
withName |
Returns a memory layout with the same characteristics as this layout, but with the given name. |
MemoryLayout |
withoutName() |
Returns a memory layout with the same characteristics as this layout, but with no name. |
long byteSize()
Optional<String> name()
MemoryLayout withName(String name)
name - the layout nameMemoryLayout withoutName()
long byteAlignment()
Layout alignment defines a power of two A which is the byte-wise alignment of the layout, where A is the number of bytes that must be aligned for any pointer that correctly points to this layout. Thus:
A=1 means unaligned (in the usual sense), which is common in packets.A=8 means word aligned (on LP64), A=4 int aligned, A=2 short aligned, etc.A=64 is the most strict alignment required by the x86/SV ABI (for AVX-512 data).withByteAlignment(long)), then this method returns the natural alignment constraint (in bytes) associated with this layout.MemoryLayout withByteAlignment(long byteAlignment)
byteAlignment - the layout alignment constraint, expressed in bytesIllegalArgumentException - if byteAlignment is not a power of twolong scale(long offset, long index)
offset + (byteSize() * index).offset - the base offsetindex - the index to be scaled by the byte size of this layoutoffset + (byteSize() * index)IllegalArgumentException - if offset or index is negativeArithmeticException - if either the addition or multiplication overflowsMethodHandle scaleHandle()
scale(long, long) on this layout.scale(long, long) on this layoutlong byteOffset(MemoryLayout.PathElement... elements)
elements - the layout path elementselements
IllegalArgumentException - if the layout path is not well-formed for this layoutIllegalArgumentException - if the layout path contains one or more open path elements
IllegalArgumentException - if the layout path contains one or more dereference path elements
MethodHandle byteOffsetHandle(MemoryLayout.PathElement... elements)
The returned method handle has the following characteristics:
long;long parameter representing the base offset;long, one for each open path element in the provided layout path. The order of these parameters corresponds to the order in which the open path elements occur in the provided layout path. The final offset returned by the method handle is computed as follows:
whereoffset = b + c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n)
b represents the base offset provided as a dynamic long argument, x_1, x_2, ... x_n represent indices into sequences provided as dynamic long arguments, whereas s_1, s_2, ... s_n are static stride constants derived from the size of the element layout of a sequence, and c_1, c_2, ... c_m are other static offset constants (such as field offsets) which are derived from the layout path. For any given dynamic argument x_i, it must be that 0 <= x_i < size_i, where size_i is the size of the open path element associated with x_i. Otherwise, the returned method handle throws IndexOutOfBoundsException. Moreover, the value of b must be such that the computation for offset does not overflow, or the returned method handle throws ArithmeticException.
byteOffset(PathElement...), but more flexibly, as some indices can be specified when invoking the method handle.elements - the layout path elementsIllegalArgumentException - if the layout path is not well-formed for this layoutIllegalArgumentException - if the layout path contains one or more dereference path elements
VarHandle varHandle(MemoryLayout.PathElement... elements)
The returned var handle has the following characteristics:
MemorySegment representing the accessed segmentlong parameter, corresponding to the base offset, denoted as B;long, one for each open path element in the provided layout path, denoted as I1, I2, ... In, respectively. The order of these access coordinates corresponds to the order in which the open path elements occur in the provided layout path. If the provided layout path P contains no dereference elements, then the offset O of the access operation is computed as follows:
O = this.byteOffsetHandle(P).invokeExact(B, I1, I2, ... In);
Accessing a memory segment using the var handle returned by this method is subject to the following checks:
IllegalArgumentException is thrown. Note that the alignment constraint of the root layout can be more strict (but not less) than the alignment constraint of the selected value layout.IndexOutOfBoundsException is thrown. This is the case when B + A <= S, where B is the base offset (defined above), A is the size of this layout and S is the size of the accessed memory segment. Note that the size of this layout might be bigger than the size of the accessed layout (e.g. when accessing a struct member).S, its corresponding trailing long coordinate value I must be 0 <= I < S, or an IndexOutOfBoundsException is thrown.accessible from the thread performing the access operation, or a WrongThreadException is thrown.read only, or an IllegalArgumentException is thrown.IllegalStateException is thrown. If the selected layout is an address layout, calling VarHandle.get(Object...) on the returned var handle will return a new memory segment. The segment is associated with the global scope. Moreover, the size of the segment depends on whether the address layout has a target layout. More specifically:
T, then the size of the returned segment is T.byteSize();VarHandle.set(Object...) can throw IllegalArgumentException if the memory segment representing the address to be written is not a native memory segment. If the provided layout path has size m and contains a dereference path element in position k (where k <= m) then two layout paths P and Q are derived, where P contains all the path elements from 0 to k - 1 and Q contains all the path elements from k + 1 to m (Q could be an empty layout path if k == m). Then, the returned var handle is computed as follows:
VarHandle baseHandle = this.varHandle(P);
MemoryLayout target = ((AddressLayout)this.select(P)).targetLayout().get();
VarHandle targetHandle = target.varHandle(Q);
targetHandle = MethodHandles.insertCoordinates(targetHandle, 1, 0L); // always access nested targets at offset 0
targetHandle = MethodHandles.collectCoordinates(targetHandle, 0,
baseHandle.toMethodHandle(VarHandle.AccessMode.GET));
As an example, consider the memory layout expressed by a GroupLayout instance constructed as follows:
GroupLayout grp = java.lang.foreign.MemoryLayout.structLayout(
MemoryLayout.paddingLayout(4),
ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN).withName("value")
);
value, we can construct a var handle as follows: VarHandle handle = grp.varHandle(PathElement.groupElement("value")); //(MemorySegment, long) -> int
elements - the layout path elementsIllegalArgumentException - if the layout path is not well-formed for this layoutIllegalArgumentException - if the layout selected by the provided path is not a value layout
VarHandle arrayElementVarHandle(MemoryLayout.PathElement... elements)
The returned var handle has the following characteristics:
MemorySegment representing the accessed segmentlong parameter, corresponding to the base offset, denoted as B;long parameter, corresponding to the array index, denoted as I0. The array index is used to scale the accessed offset by this layout size;long, one for each open path element in the provided layout path, denoted as I1, I2, ... In, respectively. The order of these access coordinates corresponds to the order in which the open path elements occur in the provided layout path. If the provided layout path P contains no dereference elements, then the offset O of the access operation is computed as follows:
O = this.byteOffsetHandle(P).invokeExact(this.scale(B, I0), I1, I2, ... In);
More formally, the method handle returned by this method is obtained from varHandle(PathElement...), as follows:
MethodHandles.collectCoordinates(varHandle(elements), 1, scaleHandle())
Accessing a memory segment using the var handle returned by this method is subject to the following checks:
IllegalArgumentException is thrown. Note that the alignment constraint of the root layout can be more strict (but not less) than the alignment constraint of the selected value layout.IndexOutOfBoundsException is thrown. This is the case when B + A <= S, where B is the base offset (defined above), A is the size of this layout and S is the size of the accessed memory segment. Note that the size of this layout might be bigger than the size of the accessed layout (e.g. when accessing a struct member).S, its corresponding trailing long coordinate value I must be 0 <= I < S, or an IndexOutOfBoundsException is thrown.accessible from the thread performing the access operation, or a WrongThreadException is thrown.read only, or an IllegalArgumentException is thrown.IllegalStateException is thrown.I0 is not bound by any sequence layout, it can assume any non-negative value - provided that the resulting offset computation does not overflow, or that the computed offset does not fall outside the spatial bound of the accessed memory segment. As such, the var handles returned from this method can be especially useful when accessing variable-length arrays.elements - the layout path elementsIllegalArgumentException - if the layout path is not well-formed for this layoutIllegalArgumentException - if the layout selected by the provided path is not a value layout
MethodHandle sliceHandle(MemoryLayout.PathElement... elements)
The returned method handle has the following characteristics:
MemorySegment;MemorySegment corresponding to the memory segment to be slicedlong parameter, corresponding to the base offsetlong, one for each open path element in the provided layout path. The order of these parameters corresponds to the order in which the open path elements occur in the provided layout path. The offset O of the returned segment is computed as if by a call to a byte offset handle constructed using the given path elements.
Computing a slice of a memory segment using the method handle returned by this method is subject to the following checks:
IllegalArgumentException will be issued. Note that the alignment constraint of the root layout can be more strict (but not less) than the alignment constraint of the selected layout.IndexOutOfBoundsException is thrown. This is the case when B + A <= S, where B is the base offset (defined above), A is the size of this layout and S is the size of the accessed memory segment. Note that the size of this layout might be bigger than the size of the accessed layout (e.g. when accessing a struct member).S, its corresponding trailing long coordinate value I must be 0 <= I < S, or an IndexOutOfBoundsException is thrown.MemorySegment.asSlice(long, long), but more flexibly, as some indices can be specified when invoking the method handle.elements - the layout path elementsIllegalArgumentException - if the layout path is not well-formed for this layoutIllegalArgumentException - if the layout path contains one or more dereference path elements
MemoryLayout select(MemoryLayout.PathElement... elements)
elements - the layout path elementselements
IllegalArgumentException - if the layout path is not well-formed for this layoutIllegalArgumentException - if the layout path contains one or more dereference path elements
IllegalArgumentException - if the layout path contains one or more path elements that select one or more sequence element indices, such as MemoryLayout.PathElement.sequenceElement(long) and MemoryLayout.PathElement.sequenceElement(long, long))boolean equals(Object other)
true if and only if the specified object is also a layout, and it is equal to this layout. Two layouts are considered equal if they are of the same kind, have the same size, name and alignment constraint. Furthermore, depending on the layout kind, additional conditions must be satisfied: SequenceLayout.elementCount()), and if their element layouts (see SequenceLayout.elementLayout()) are also equal;StructLayout, UnionLayout) and if their member layouts (see GroupLayout.memberLayouts()) are also equal.static PaddingLayout paddingLayout(long byteSize)
byteSize - the padding size (expressed in bytes)IllegalArgumentException - if byteSize <= 0
static SequenceLayout sequenceLayout(long elementCount, MemoryLayout elementLayout)
elementCount - the sequence element countelementLayout - the sequence element layoutIllegalArgumentException - if elementCount is negativeIllegalArgumentException - if elementLayout.byteSize() * elementCount overflowsIllegalArgumentException - if elementLayout.byteSize() % elementLayout.byteAlignment() != 0
static StructLayout structLayout(MemoryLayout... elements)
structLayout(JAVA_SHORT, JAVA_INT);
structLayout(JAVA_SHORT, MemoryLayout.paddingLayout(2), JAVA_INT);
structLayout(JAVA_SHORT, JAVA_INT.withByteAlignment(2));
elements - The member layouts of the struct layoutIllegalArgumentException - if the sum of the byte sizes of the member layouts overflowsIllegalArgumentException - if a member layout in elements occurs at an offset (relative to the start of the struct layout) which is not compatible with its alignment constraintstatic UnionLayout unionLayout(MemoryLayout... elements)
elements - The member layouts of the union layout
© 1993, 2025, Oracle and/or its affiliates. All rights reserved.
Documentation extracted from Debian's OpenJDK Development Kit package.
Licensed under the GNU General Public License, version 2, with the Classpath Exception.
Various third party code in OpenJDK is licensed under different licenses (see Debian package).
Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates.
https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/foreign/MemoryLayout.html