Интерфейс MemoryLayout
- Все известные подинтерфейсы:
AddressLayout, GroupLayout, PaddingLayout, SequenceLayout, StructLayout, UnionLayout, ValueLayout, ValueLayout.OfBoolean, ValueLayout.OfByte, ValueLayout.OfChar, ValueLayout.OfDouble, ValueLayout.OfFloat, ValueLayout.OfInt, ValueLayout.OfLong, ValueLayout.OfShort
public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, PaddingLayout, ValueLayout
В иерархии компоновок есть два листовых типа: компоновки значений, которые используются для представления значений заданного размера и типа, и компоновки-заполнители, которые, как следует из названия, используются для представления области сегмента памяти, содержимое которой следует игнорировать и которая предназначена главным образом для выравнивания. Некоторые распространённые константы компоновок значений, такие как ValueLayout.JAVA_INT и ValueLayout.JAVA_FLOAT_UNALIGNED, определены в классе ValueLayout. Особый вид компоновки значений — компоновка адреса — используется для моделирования значений, обозначающих адрес области памяти.
Более сложные компоновки можно получить из простых: компоновка последовательности обозначает однородное повторение нуля или более экземпляров компоновки элемента; групповая компоновка обозначает неоднородное объединение нуля или более компоновок-членов. Групповые компоновки бывают двух видов: компоновки структур, в которых компоновки-члены располагаются одна за другой, и компоновки объединений, в которых компоновки-члены располагаются с одним и тем же начальным смещением.
Компоновкам можно при необходимости назначить имя. На имя компоновки можно ссылаться при создании путей компоновки.
Рассмотрим следующее объявление структуры на 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.carrier(), связанным с этой компоновкой значения. То есть константа
ValueLayout.JAVA_INTимеет тип-переносчикintи размер 4 байта; - Размер компоновки адреса зависит от платформы. То есть константа
ValueLayout.ADDRESSимеет размер 8 байт на 64-разрядной платформе; - Размер компоновки-заполнителя всегда задаётся явно при создании;
- Размер компоновки последовательности с компоновкой элемента E и количеством элементов L равен размеру E, умноженному на L;
- Размер компоновки структуры с компоновками-членами M1, M2, ... Mn, размеры которых равны соответственно S1, S2, ... Sn, равен S1 + S2 + ... + Sn;
- Размер компоновки объединения U с компоновками-членами M1, M2, ... Mn, размеры которых равны соответственно S1, S2, ... Sn, равен max(S1, S2, ... Sn).
Кроме того, у всех компоновок есть естественное выравнивание (выраженное в байтах), которое определяется следующим образом:
- Естественное выравнивание компоновки-заполнителя равно 1;
- Естественное выравнивание компоновки значения размером N равно N;
- Естественное выравнивание компоновки последовательности с компоновкой элемента E равно выравниванию E;
- Естественное выравнивание групповой компоновки с компоновками-членами M1, M2, ... Mn, выравнивания которых равны соответственно A1, A2, ... An, равно max(A1, A2 ... An).
withByteAlignment(long)). Это может быть полезно для описания компоновок с менее строгими или более строгими требованиями к выравниванию. Пути компоновки
Путь компоновки используется для однозначного выбора компоновки, вложенной в другую компоновку. Пути компоновки обычно представляются последовательностью из одного или нескольких элементов пути. (Более формальное определение путей компоновки приведено ниже).Пути компоновки можно использовать, чтобы:
- получать смещения произвольно вложенных компоновок;
- получать дескриптор переменной, с помощью которого можно получить доступ к значению, соответствующему выбранной компоновке;
- выбирать произвольно вложенную компоновку.
Например, для созданной выше компоновки последовательности taggedValues можно получить смещение в байтах компоновки-члена с именем value в первом элементе последовательности следующим образом:
long valueOffset = TAGGED_VALUES.byteOffset(PathElement.sequenceElement(0),
PathElement.groupElement("value")); // yields 4
value: MemoryLayout value = TAGGED_VALUES.select(PathElement.sequenceElement(),
PathElement.groupElement("value"));
Открытые элементы пути
Некоторые элементы пути компоновки, называемые открытыми элементами пути, могут одновременно выбирать несколько компоновок. Например, открытые элементы путиMemoryLayout.PathElement.sequenceElement(), MemoryLayout.PathElement.sequenceElement(long, long) выбирают неопределённый элемент в компоновке последовательности. Дескриптор переменной, полученный из пути компоновки, содержащего один или несколько открытых элементов пути, имеет дополнительные координаты типа long, которые клиенты могут использовать для привязки открытых элементов пути: 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
Открытые элементы пути также влияют на создание дескрипторов метода для вычисления смещения. Каждый открытый элемент пути становится дополнительным параметром типа long в полученном дескрипторе метода. Этот параметр можно использовать для указания индекса элемента последовательности, смещение которого требуется вычислить:
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, компоновку адреса, целевой компоновкой которой является компоновка последовательности из четырёх компоновок структур. Каждая компоновка структуры описывает двумерную точку и задаётся парой координат ValueLayout.JAVA_INT с именами x и y соответственно. С помощью элементов пути разыменования можно получить дескриптор переменной, который обращается к координате y одной из точек прямоугольника, следующим образом:
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, также называемой исходной компоновкой. Каждый элемент пути в пути компоновки можно рассматривать как функцию, которая обновляет текущую компоновку C_i-1 до некоторой другой компоновки C_i. Иными словами, для каждого элемента пути E1, E2, ... En в пути компоновки P вычисляется C_i = f_i(C_i-1), где f_i — функция выбора, связанная с рассматриваемым элементом пути, обозначаемая как E_i. Итоговая компоновка C_i также называется выбранной компоновкой. Путь компоновки P считается корректным для исходной компоновки C_0, если все его элементы пути E1, E2, ... En корректны для соответствующих входных компоновок C_0, C_1, ... C_n-1. Элемент пути E считается корректным для компоновки L, если выполняется любое из следующих условий:
-
Lявляется компоновкой последовательности, аE— элементом пути последовательности (одним изMemoryLayout.PathElement.sequenceElement(long),MemoryLayout.PathElement.sequenceElement(long, long)илиMemoryLayout.PathElement.sequenceElement()). Кроме того, еслиEсодержит один или несколько индексов последовательности, эти индексы должны быть совместимы с количеством элементов компоновки последовательности; -
Lявляется групповой компоновкой, аE— элементом пути группы (одним изMemoryLayout.PathElement.groupElement(String)илиMemoryLayout.PathElement.groupElement(long)). Кроме того, элемент пути группы должен ссылаться на допустимую компоновку-член вL— по имени или индексу; -
Lявляется компоновкой адреса, аE— элементом пути разыменования. Кроме того,Lдолжна определять некоторую целевую компоновку.
P, который некорректен для исходной компоновки C_0, приведёт к выбросу исключения IllegalArgumentException. Ограничения режимов доступа
Дескриптор переменной, возвращаемый методомvarHandle(PathElement...) или ValueLayout.varHandle(), обладает определёнными характеристиками доступа, которые определяются выбранной компоновкой L: - Тип-переносчик
T, определяемый поL.carrier() - Ограничение выравнивания
A, определяемое поL.byteAlignment() - Размер доступа
S, определяемый поL.byteSize()
A совместимо с размером доступа S, то есть если A >= S. Гарантируется, что выровненный дескриптор переменной поддерживает следующие режимы доступа: - режимы доступа для чтения и записи для всех
T. Режимы доступаgetиsetдляlong,doubleиMemorySegmentподдерживаются, но не гарантируют атомарность, как описано в разделе 17.7 спецификации Язык программирования Java. - режимы атомарного обновления для
int,long,float,doubleиMemorySegment. (В будущих основных выпусках платформы JDK для некоторых режимов доступа, которые сейчас не поддерживаются, могут быть добавлены дополнительные типы.) - режимы числового атомарного обновления для
int,longиMemorySegment. (В будущих основных выпусках платформы JDK для некоторых режимов доступа, которые сейчас не поддерживаются, могут быть добавлены дополнительные числовые типы.) - режимы побитового атомарного обновления для
int,longиMemorySegment. (В будущих основных выпусках платформы JDK для некоторых режимов доступа, которые сейчас не поддерживаются, могут быть добавлены дополнительные числовые типы.)
T — это float, double или MemorySegment, то режимы атомарного обновления сравнивают значения, используя их побитовое представление (см. Float.floatToRawIntBits(float), Double.doubleToRawLongBits(double) и MemorySegment.address() соответственно). В противном случае дескриптор переменной называется невыровненным, если его ограничение выравнивания A несовместимо с размером доступа S, то есть если A < S. Невыровненный дескриптор переменной поддерживает только режимы доступа get и set. При использовании любых других режимов доступа будет выброшено исключение UnsupportedOperationException. Кроме того, хотя режимы доступа get и set поддерживаются, они могут привести к разрыву слова.
Работа с массивами переменной длины
Мы рассмотрели, как компоновки последовательностей используются для описания содержимого массива, размер которого известен статически. Однако бывают случаи, когда размер массива известен только динамически. Такие массивы называются массивами переменной длины. Существует два распространённых вида массивов переменной длины:- массив переменной длины верхнего уровня, размер которого зависит от значения некоторой не связанной с ним переменной или параметра;
- массив переменной длины, вложенный в структуру, размер которого зависит от значения другого поля во внешней структуре.
Массивы переменной длины верхнего уровня
Рассмотрим следующее объявление структуры на C:typedef struct {
int x;
int y;
} Point;
x и y). Теперь рассмотрим следующий фрагмент кода на C: int size = ...
Point *points = (Point*)malloc(sizeof(Point) * size);
for (int i = 0 ; i < size ; i++) {
... points[i].x ...
}
points). Важно, что размер массива динамически определяется значением переменной size. Внутри цикла выполняется обращение к координате x всех точек массива. Чтобы смоделировать этот код на Java, сначала определим компоновку структуры Point следующим образом:
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 последующих точек массива обращаются с помощью дескриптора переменной POINT_ARR_X, полученного методом arrayElementVarHandle(PathElement...). У этого дескриптора переменной есть две координаты long: первая — базовое смещение (равное 0L), а вторая — логический индекс, который позволяет перемещаться по элементам массива точек. Координата базового смещения позволяет клиентам задавать сложные операции доступа, добавляя дополнительные вычисления смещения в дескриптор переменной (пример будет приведён ниже). Если базовое смещение постоянно (как в предыдущем примере), клиенты при желании могут исключить параметр базового смещения и упростить выражение доступа. Это можно сделать с помощью адаптера дескриптора переменной MethodHandles.insertCoordinates(VarHandle, int, Object...).
Вложенные массивы переменной длины
Рассмотрим следующее объявление структуры на C:typedef struct {
int size;
Point points[];
} Polygon;
points в объявлении на C оставлен неуказанным с использованием гибкого элемента массива (функция, стандартизированная в C99). И здесь клиенты могут выполнять структурированный доступ к элементам вложенного массива переменной длины с помощью метода arrayElementVarHandle(PathElement...), как показано ниже:
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 содержит компоновку последовательности нулевого размера. Компоновка элемента этой последовательности — показанная ранее компоновка POINT. Компоновка многоугольника используется для получения дескриптора переменной, обеспечивающего доступ к размеру многоугольника, а также смещения (POINTS_OFFSET) до начала массива переменной длины points. Затем к координатам x всех точек многоугольника можно обращаться следующим образом:
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. Затем в цикле считываем координаты x всех точек многоугольника. Для этого координате смещения дескриптора переменной POINT_ARR_X передаётся пользовательское смещение (а именно POINTS_OFFSET). Как и прежде, переменная цикла i передаётся в качестве индекса дескриптора переменной POINT_ARR_X, чтобы перемещаться по всем элементам массива переменной длины.- Требования к реализации:
- Реализации этого интерфейса неизменяемы, потокобезопасны и основаны на значениях.
- Граф запечатанной иерархии классов:
- Начиная с версии:
- 22
Краткое описание вложенных классов
| Модификатор и тип | Интерфейс | Описание |
|---|---|---|
static interface |
MemoryLayout.PathElement |
Элемент пути компоновки. |
Краткое описание методов
| Модификатор и тип | Метод | Описание |
|---|---|---|
VarHandle |
arrayElementVarHandle |
Создаёт дескриптор переменной, который обращается к соседним элементам сегмента памяти со смещениями, выбранными заданным путём компоновки, где компоновки доступных элементов совпадают с этой компоновкой, а исходная компоновка в пути — эта компоновка. |
long |
byteAlignment() |
Возвращает ограничение выравнивания, связанное с этой компоновкой и выраженное в байтах. |
long |
byteOffset |
Вычисляет смещение в байтах компоновки, выбранной заданным путём компоновки, где исходная компоновка в пути — эта компоновка. |
MethodHandle |
byteOffsetHandle |
Создаёт дескриптор метода, вычисляющий смещение в байтах компоновки, выбранной заданным путём компоновки, где исходная компоновка в пути — эта компоновка. |
long |
byteSize() |
Возвращает размер компоновки в байтах. |
boolean |
equals |
Сравнивает указанный объект с этой компоновкой на равенство. |
int |
hashCode() |
Возвращает хеш-код этой компоновки. |
Optional |
name() |
Возвращает имя (если оно есть), связанное с этой компоновкой. |
static PaddingLayout |
paddingLayout |
Создаёт компоновку-заполнитель заданного размера в байтах. |
long |
scale |
Возвращает offset + (byteSize() * index). |
MethodHandle |
scaleHandle() |
Возвращает дескриптор метода, который можно использовать для вызова scale(long, long) для этой компоновки. |
MemoryLayout |
select |
Возвращает компоновку, выбранную по указанному пути, где исходная компоновка в пути — эта компоновка. |
static SequenceLayout |
sequenceLayout |
Создаёт компоновку последовательности с заданной компоновкой элемента и количеством элементов. |
MethodHandle |
sliceHandle |
Создаёт дескриптор метода, который для заданного сегмента памяти возвращает срез, соответствующий компоновке, выбранной заданным путём компоновки, где исходная компоновка в пути — эта компоновка. |
static StructLayout |
structLayout |
Создаёт компоновку структуры с заданными компоновками-членами. |
String |
toString() |
Возвращает строковое представление этой компоновки. |
static UnionLayout |
unionLayout |
Создаёт компоновку объединения с заданными компоновками-членами. |
VarHandle |
varHandle |
Создаёт дескриптор переменной, который обращается к сегменту памяти со смещением, выбранным заданным путём компоновки, где исходная компоновка в пути — эта компоновка. |
MemoryLayout |
withByteAlignment |
Возвращает компоновку памяти с теми же характеристиками, что и у этой компоновки, но с заданным ограничением выравнивания (в байтах). |
MemoryLayout |
withName |
Возвращает компоновку памяти с теми же характеристиками, что и у этой компоновки, но с заданным именем. |
MemoryLayout |
withoutName() |
Возвращает компоновку памяти с теми же характеристиками, что и у этой компоновки, но без имени. |
Подробное описание методов
byteSize
long byteSize()
- Возвращает:
- размер макета в байтах
name
Optional<String> name()
- Возвращает:
- имя (если оно есть), связанное с этим макетом
- См. также:
withName
MemoryLayout withName(String name)
- Параметры:
-
name— имя макета - Возвращает:
- макет памяти с теми же характеристиками, что и у этого макета, но с заданным именем
- См. также:
withoutName
MemoryLayout withoutName()
- Примечание к API:
- Это может быть полезно для сравнения двух макетов, имеющих разные имена, но в остальном равных.
- Возвращает:
- макет памяти с теми же характеристиками, что и у этого макета, но без имени
- См. также:
byteAlignment
long byteAlignment()
Выравнивание макета задаёт степень двойки A, которая является выравниванием макета по границе байта, где A — число байтов, по которому должен быть выровнен любой указатель, корректно указывающий на этот макет. Таким образом:
-
A=1означает отсутствие выравнивания (в обычном смысле), что часто встречается в пакетах. -
A=8означает выравнивание по слову (в LP64),A=4— выравнивание по int,A=2— выравнивание по short и т. д. -
A=64— наиболее строгое выравнивание, требуемое ABI x86/SV (для данных AVX-512).
withByteAlignment(long)), этот метод возвращает ограничение естественного выравнивания (в байтах), связанное с этим макетом.- Возвращает:
- ограничение выравнивания, связанное с этим макетом и выраженное в байтах
withByteAlignment
MemoryLayout withByteAlignment(long byteAlignment)
- Параметры:
-
byteAlignment— ограничение выравнивания макета, выраженное в байтах - Возвращает:
- макет памяти с теми же характеристиками, что и у этого макета, но с заданным ограничением выравнивания (в байтах)
- Вызывает исключение:
-
IllegalArgumentException— еслиbyteAlignmentне является степенью двойки
scale
long scale(long offset, long index)
offset + (byteSize() * index).- Параметры:
-
offset— базовое смещение -
index— индекс, масштабируемый на размер этого макета в байтах - Возвращает:
offset + (byteSize() * index)- Вызывает исключение:
-
IllegalArgumentException— еслиoffsetилиindexотрицательно -
ArithmeticException— если происходит переполнение при сложении или умножении
scaleHandle
MethodHandle scaleHandle()
scale(long, long) для этого макета.- Возвращает:
- дескриптор метода, который можно использовать для вызова
scale(long, long)для этого макета
byteOffset
long byteOffset(MemoryLayout.PathElement... elements)
- Параметры:
-
elements— элементы пути макета - Возвращает:
- Смещение в байтах макета, выбранного путём макета в
elements - Вызывает исключение:
-
IllegalArgumentException— если путь макета имеет некорректную форму для этого макета -
IllegalArgumentException— если путь макета содержит один или несколько открытых элементов пути -
IllegalArgumentException— если путь макета содержит один или несколько элементов пути разыменования
byteOffsetHandle
MethodHandle byteOffsetHandle(MemoryLayout.PathElement... elements)
Возвращённый дескриптор метода имеет следующие характеристики:
- его тип возвращаемого значения —
long; - у него есть один начальный параметр типа
long, представляющий базовое смещение; - у него есть ноль или более конечных параметров типа
long— по одному для каждого открытого элемента пути в предоставленном пути макета. Порядок этих параметров соответствует порядку открытых элементов пути в предоставленном пути макета.
Итоговое смещение, возвращаемое дескриптором метода, вычисляется следующим образом:
гдеoffset = b + c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n)
b представляет базовое смещение, переданное в качестве динамического аргумента long, x_1, x_2, ... x_n представляют индексы в последовательностях, переданные в качестве динамических аргументов long, тогда как s_1, s_2, ... s_n — другие статические константы шага, полученные из размера макета элемента последовательности, а c_1, c_2, ... c_m — другие статические константы смещения (например, смещения полей), полученные из пути макета. Для любого динамического аргумента x_i должно выполняться условие 0 <= x_i < size_i, где size_i — размер открытого элемента пути, связанного с x_i. В противном случае возвращённый дескриптор метода выбрасывает исключение IndexOutOfBoundsException. Кроме того, значение b должно быть таким, чтобы вычисление offset не приводило к переполнению; иначе возвращённый дескриптор метода выбрасывает исключение ArithmeticException.
- Примечание к API:
- Возвращённый дескриптор метода можно использовать для вычисления смещения макета аналогично
byteOffset(PathElement...), но более гибким образом, поскольку некоторые индексы можно задать при вызове дескриптора метода. - Параметры:
-
elements— элементы пути макета - Возвращает:
- дескриптор метода, вычисляющий смещение в байтах макета, выбранного заданным путём макета
- Вызывает исключение:
-
IllegalArgumentException— если путь макета имеет некорректную форму для этого макета -
IllegalArgumentException— если путь макета содержит один или несколько элементов пути разыменования
varHandle
VarHandle varHandle(MemoryLayout.PathElement... elements)
Возвращённый дескриптор переменной имеет следующие характеристики:
- его тип определяется типом-переносчиком выбранного макета значения;
- у него есть начальный параметр типа
MemorySegment, представляющий сегмент, к которому выполняется обращение - за ним следует параметр
long, соответствующий базовому смещению, обозначенному какB; - у него есть ноль или более конечных координат доступа типа
long— по одной для каждого открытого элемента пути в предоставленном пути макета, обозначенных соответственно какI1, I2, ... In. Порядок этих координат доступа соответствует порядку открытых элементов пути в предоставленном пути макета.
Если предоставленный путь макета P не содержит элементов разыменования, смещение O операции доступа вычисляется следующим образом:
O = this.byteOffsetHandle(P).invokeExact(B, I1, I2, ... In);
Доступ к сегменту памяти с помощью дескриптора переменной, возвращённого этим методом, сопровождается следующими проверками:
- Физический адрес сегмента памяти, к которому выполняется обращение, должен быть выровнен в соответствии с ограничением выравнивания корневого макета (этого макета); в противном случае выбрасывается
IllegalArgumentException. Обратите внимание, что ограничение выравнивания корневого макета может быть строже (но не слабее) ограничения выравнивания выбранного макета значения. - Операция доступа должна находиться в пространственных границах сегмента памяти, к которому выполняется обращение; в противном случае выбрасывается
IndexOutOfBoundsException. Это условие выполняется, когдаB + A <= S, гдеB— базовое смещение (определённое выше),A— размер этого макета, аS— размер сегмента памяти, к которому выполняется обращение. Обратите внимание, что размер этого макета может быть больше размера макета, к которому выполняется обращение (например, при обращении к члену структуры). - Если предоставленный путь макета содержит открытый элемент пути с размером
S, значение соответствующей конечной координатыlong—I— должно быть равно0 <= I < S; в противном случае выбрасываетсяIndexOutOfBoundsException. - Сегмент памяти, к которому выполняется обращение, должен быть
accessibleдля потока, выполняющего операцию доступа; в противном случае выбрасываетсяWrongThreadException. - При операциях записи сегмент памяти, к которому выполняется обращение, не должен быть
read only; в противном случае выбрасываетсяIllegalArgumentException. - Область действия, связанная с сегментом, к которому выполняется обращение, должна быть активна; в противном случае выбрасывается
IllegalStateException.
Если выбранный макет является макетом адреса, вызов VarHandle.get(Object...) для возвращённого дескриптора переменной вернёт новый сегмент памяти. Сегмент будет связан с глобальной областью действия. Кроме того, размер сегмента зависит от того, задан ли у макета адреса целевой макет. В частности:
- Если у макета адреса задан целевой макет
T, размер возвращённого сегмента равенT.byteSize(); - В противном случае у макета адреса нет целевого макета, и размер возвращённого сегмента равен нулю.
VarHandle.set(Object...) может выбросить IllegalArgumentException, если сегмент памяти, представляющий записываемый адрес, не является нативным сегментом памяти. Если предоставленный путь макета имеет размер m и содержит элемент пути разыменования в позиции k (где k <= m), то выводятся два пути макета P и Q, где P содержит все элементы пути от 0 до k - 1, а Q содержит все элементы пути от k + 1 до m (Q может быть пустым путём макета, если k == m). Затем возвращённый дескриптор переменной вычисляется следующим образом:
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));
В качестве примера рассмотрим макет памяти, выраженный экземпляром GroupLayout, созданным следующим образом:
GroupLayout grp = java.lang.foreign.MemoryLayout.structLayout(
MemoryLayout.paddingLayout(4),
ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN).withName("value")
);
value, можно создать дескриптор переменной следующим образом: VarHandle handle = grp.varHandle(PathElement.groupElement("value")); //(MemorySegment, long) -> int
- Примечание к API:
- Полученный дескриптор переменной имеет определённые ограничения режимов доступа, общие для всех дескрипторов переменных, производных от макетов памяти.
- Параметры:
-
elements— элементы пути макета - Возвращает:
- дескриптор переменной, обращающийся к сегменту памяти по смещению, выбранному заданным путём макета
- Вызывает исключение:
-
IllegalArgumentException— если путь макета имеет некорректную форму для этого макета -
IllegalArgumentException— если макет, выбранный заданным путём, не является макетом значения
arrayElementVarHandle
VarHandle arrayElementVarHandle(MemoryLayout.PathElement... elements)
Возвращённый дескриптор переменной имеет следующие характеристики:
- его тип определяется типом-переносчиком выбранного макета значения;
- у него есть начальный параметр типа
MemorySegment, представляющий сегмент, к которому выполняется обращение - за ним следует параметр
long, соответствующий базовому смещению, обозначенному какB; - за ним следует параметр
long, соответствующий индексу массива, обозначенному какI0. Индекс массива используется для масштабирования смещения доступа на размер этого макета; - у него есть ноль или более конечных координат доступа типа
long— по одной для каждого открытого элемента пути в предоставленном пути макета, обозначенных соответственно какI1, I2, ... In. Порядок этих координат доступа соответствует порядку открытых элементов пути в предоставленном пути макета.
Если предоставленный путь макета P не содержит элементов разыменования, смещение O операции доступа вычисляется следующим образом:
O = this.byteOffsetHandle(P).invokeExact(this.scale(B, I0), I1, I2, ... In);
Формально дескриптор метода, возвращённый этим методом, получается из varHandle(PathElement...) следующим образом:
MethodHandles.collectCoordinates(varHandle(elements), 1, scaleHandle())
Доступ к сегменту памяти с помощью дескриптора переменной, возвращённого этим методом, сопровождается следующими проверками:
- Физический адрес сегмента памяти, к которому выполняется обращение, должен быть выровнен в соответствии с ограничением выравнивания корневого макета (этого макета); в противном случае выбрасывается
IllegalArgumentException. Обратите внимание, что ограничение выравнивания корневого макета может быть строже (но не слабее) ограничения выравнивания выбранного макета значения. - Операция доступа должна находиться в пространственных границах сегмента памяти, к которому выполняется обращение; в противном случае выбрасывается
IndexOutOfBoundsException. Это условие выполняется, когдаB + A <= S, гдеB— базовое смещение (определённое выше),A— размер этого макета, аS— размер сегмента памяти, к которому выполняется обращение. Обратите внимание, что размер этого макета может быть больше размера макета, к которому выполняется обращение (например, при обращении к члену структуры). - Если предоставленный путь макета содержит открытый элемент пути с размером
S, значение соответствующей конечной координатыlong—I— должно быть равно0 <= I < S; в противном случае выбрасываетсяIndexOutOfBoundsException. - Сегмент памяти, к которому выполняется обращение, должен быть
accessibleдля потока, выполняющего операцию доступа; в противном случае выбрасываетсяWrongThreadException. - При операциях записи сегмент памяти, к которому выполняется обращение, не должен быть
read only; в противном случае выбрасываетсяIllegalArgumentException. - Область действия, связанная с сегментом, к которому выполняется обращение, должна быть активна; в противном случае выбрасывается
IllegalStateException.
- Примечание к API:
- Поскольку начальная координата индекса
I0не ограничена никаким макетом последовательности, она может принимать любое неотрицательное значение при условии, что вычисление итогового смещения не приводит к переполнению и вычисленное смещение не выходит за пространственные границы сегмента памяти, к которому выполняется обращение. Поэтому дескрипторы переменных, возвращаемые этим методом, могут быть особенно полезны при работе с массивами переменной длины. - Параметры:
-
elements— элементы пути макета - Возвращает:
- дескриптор переменной, обращающийся к соседним элементам сегмента памяти по смещениям, выбранным заданным путём макета
- Вызывает исключение:
-
IllegalArgumentException— если путь макета имеет некорректную форму для этого макета -
IllegalArgumentException— если макет, выбранный заданным путём, не является макетом значения
sliceHandle
MethodHandle sliceHandle(MemoryLayout.PathElement... elements)
Возвращённый дескриптор метода имеет следующие характеристики:
- его тип возвращаемого значения —
MemorySegment; - у него есть начальный параметр типа
MemorySegment, соответствующий сегменту памяти, который необходимо нарезать - за ним следует параметр
long, соответствующий базовому смещению - у него есть ноль или более конечных параметров типа
long— по одному для каждого открытого элемента пути в предоставленном пути макета. Порядок этих параметров соответствует порядку открытых элементов пути в предоставленном пути макета.
Смещение O возвращённого сегмента вычисляется так же, как при вызове дескриптора смещения в байтах, созданного с использованием заданных элементов пути.
Вычисление среза сегмента памяти с помощью дескриптора метода, возвращённого этим методом, сопровождается следующими проверками:
- Физический адрес сегмента памяти, к которому выполняется обращение, должен быть выровнен в соответствии с ограничением выравнивания корневого макета (этого макета); в противном случае будет выброшено
IllegalArgumentException. Обратите внимание, что ограничение выравнивания корневого макета может быть строже (но не слабее) ограничения выравнивания выбранного макета. - Операция создания среза должна находиться в пространственных границах сегмента памяти, к которому выполняется обращение; в противном случае выбрасывается
IndexOutOfBoundsException. Это условие выполняется, когдаB + A <= S, гдеB— базовое смещение (определённое выше),A— размер этого макета, аS— размер сегмента памяти, к которому выполняется обращение. Обратите внимание, что размер этого макета может быть больше размера макета, к которому выполняется обращение (например, при обращении к члену структуры). - Если предоставленный путь макета содержит открытый элемент пути с размером
S, значение соответствующей конечной координатыlong—I— должно быть равно0 <= I < S; в противном случае выбрасываетсяIndexOutOfBoundsException.
- Примечание к API:
- Возвращённый дескриптор метода можно использовать для получения среза сегмента памяти аналогично
MemorySegment.asSlice(long, long), но более гибким образом, поскольку некоторые индексы можно задать при вызове дескриптора метода. - Параметры:
-
elements— элементы пути макета - Возвращает:
- дескриптор метода, используемый для создания среза сегмента памяти по смещению, выбранному заданным путём макета
- Вызывает исключение:
-
IllegalArgumentException— если путь макета имеет некорректную форму для этого макета -
IllegalArgumentException— если путь макета содержит один или несколько элементов пути разыменования
select
MemoryLayout select(MemoryLayout.PathElement... elements)
- Параметры:
-
elements— элементы пути макета - Возвращает:
- макет, выбранный путём макета в
elements - Вызывает исключение:
-
IllegalArgumentException— если путь макета имеет некорректную форму для этого макета -
IllegalArgumentException— если путь макета содержит один или несколько элементов пути разыменования -
IllegalArgumentException— если путь макета содержит один или несколько элементов пути, выбирающих один или несколько индексов элементов последовательности, напримерMemoryLayout.PathElement.sequenceElement(long)иMemoryLayout.PathElement.sequenceElement(long, long))
equals
boolean equals(Object other)
true тогда и только тогда, когда указанный объект также является макетом и равен этому макету. Два макета считаются равными, если они имеют один и тот же вид, одинаковые размер, имя и ограничение выравнивания. Кроме того, в зависимости от вида макета должны выполняться дополнительные условия: - два макета значения считаются равными, если у них одинаковые порядок байтов и тип-переносчик. Кроме того, два макета адреса считаются равными, если у них также одинаковый целевой макет;
- два макета последовательности считаются равными, если у них одинаковое количество элементов (см.
SequenceLayout.elementCount()) и равны их макеты элементов (см.SequenceLayout.elementLayout()); - два групповых макета считаются равными, если они имеют один и тот же тип (см.
StructLayout,UnionLayout) и равны их макеты членов (см.GroupLayout.memberLayouts()).
hashCode
toString
paddingLayout
static PaddingLayout paddingLayout(long byteSize)
- Параметры:
-
byteSize— размер заполнения (в байтах) - Возвращает:
- новый макет селектора
- Вызывает исключение:
-
IllegalArgumentException— еслиbyteSize <= 0
sequenceLayout
static SequenceLayout sequenceLayout(long elementCount, MemoryLayout elementLayout)
- Параметры:
-
elementCount— количество элементов последовательности -
elementLayout— макет элемента последовательности - Возвращает:
- новый макет последовательности с заданным макетом элемента и размером
- Вызывает исключение:
-
IllegalArgumentException— еслиelementCountотрицательно -
IllegalArgumentException— если происходит переполнениеelementLayout.byteSize() * elementCount -
IllegalArgumentException— еслиelementLayout.byteSize() % elementLayout.byteAlignment() != 0
structLayout
static StructLayout structLayout(MemoryLayout... elements)
- Примечание к API:
- Эта фабрика не выравнивает автоматически компоновки элементов, добавляя дополнительные элементы компоновки заполнения. Поэтому создание следующей структурной компоновки завершится исключением: Чтобы избежать исключения, клиенты могут добавить дополнительные элементы компоновки заполнения:
structLayout(JAVA_SHORT, JAVA_INT);Или же можно использовать компоновку элемента с менее строгим ограничением на выравнивание. В результате получится упакованная структурная компоновка:structLayout(JAVA_SHORT, MemoryLayout.paddingLayout(2), JAVA_INT);structLayout(JAVA_SHORT, JAVA_INT.withByteAlignment(2)); - Параметры:
-
elements- Компоновки элементов структурной компоновки - Возвращает:
- структурную компоновку с заданными компоновками элементов
- Вызывает исключение:
-
IllegalArgumentException- если сумма размеров в байтах компоновок элементов переполняется -
IllegalArgumentException- если элемент компоновки вelementsнаходится по смещению (относительно начала структурной компоновки), несовместимому с его ограничением на выравнивание
unionLayout
static UnionLayout unionLayout(MemoryLayout... elements)
- Параметры:
-
elements- Компоновки элементов объединенной компоновки - Возвращает:
- объединенную компоновку с заданными компоновками элементов
© 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