接口 MemoryLayout

所有父级接口:
Constable
所有已知的实现类:
GroupLayout , SequenceLayout , ValueLayout

public sealed interface MemoryLayout extends Constable permits SequenceLayout , GroupLayout , ValueLayout (not exhaustive)
内存布局可用于以 language neutral 方式描述内存段的内容。布局层次结构中有两个叶子, value layouts ,用于表示给定大小和种类的值(请参阅 ValueLayout )和 padding layouts ,顾名思义,用于表示内存段的一部分,其内容应被忽略,并且主要是出于对齐原因而存在(请参阅 paddingLayout(long) )。一些常见的值布局常量在 MemoryLayouts 类中定义。

更复杂的布局可以从更简单的布局中派生出来:a sequence layout 表示一个或多个元素布局的重复(请参阅 SequenceLayout ); a group layout 表示(通常)异构成布局的聚合(请参阅 GroupLayout )。

例如,考虑以下 C 中的结构声明:


 typedef struct {
   char kind;
   int value;
 } TaggedValues[5];
  
上面的声明可以使用布局对象建模,如下所示:

SequenceLayout taggedValues = MemoryLayout.sequenceLayout(5,
  MemoryLayout.structLayout(
    MemoryLayout.valueLayout(8, ByteOrder.nativeOrder()).withName("kind"),
    MemoryLayout.paddingLayout(24),
    MemoryLayout.valueLayout(32, ByteOrder.nativeOrder()).withName("value")
  )
).withName("TaggedValues");
  

该接口的所有实现都必须是 value-based ;程序应将 equal 的实例视为可互换的,并且不应使用实例进行同步,否则可能会发生不可预测的行为。例如,在未来的版本中,同步可能会失败。应使用 equals 方法进行比较。

非平台类不应直接实现 MemoryLayout

除非另有指定,否则将 null 参数或包含一个或多个 null 元素的数组参数传递给此类中的方法会导致抛出 NullPointerException

大小、对齐和字节顺序

所有布局都有尺寸;值和填充布局的布局大小始终明确表示;这意味着无论在哪个平台上使用,布局描述总是具有相同的位大小。对于派生布局,大小计算如下:
  • 对于元素布局为 E 且大小为 L 的 finite 序列布局 SS 的大小为 E 的大小乘以 L
  • unbounded 序列布局的大小是 unknown
  • 对于具有成员布局 M1M2、...Mn 的组布局 G,其大小分别为 S1S2、...SnG 的大小为 S1 + S2 + ... + Snmax(S1, S2, ... Sn) 取决于组是 struct 还是 union , 分别

此外,所有布局都有一个 natural alignment 可以推断如下:

  • 对于 padding 布局 L ,自然对齐是 1,不管它的大小;也就是说,在没有显式对齐约束的情况下,填充布局不应影响它嵌套到的组布局的对齐约束
  • 对于大小为 N 的值布局 LL 的自然对齐方式为 N
  • 对于元素布局为 E 的序列布局 SS 的自然对齐是 E 的自然对齐
  • 对于组布局 G 和成员布局 M1 , M2 , ... Mn 其对齐方式分别为 A1 , A2 , ... An , G 的自然对齐方式为 max(A1, A2 ... An)
如果需要,可以覆盖布局的自然对齐方式(请参阅 withBitAlignment(long) ),这对于描述超对齐布局很有用。

所有值布局都有一个 explicit 字节顺序(请参阅 ByteOrder ),该顺序是在创建布局时设置的。

布局路径

layout path 源自 root 布局(通常是组或序列布局),并终止于嵌套在根布局内的布局 - 这是布局路径的布局 selected。布局路径通常表示为一个或多个 MemoryLayout.PathElement 实例的序列。

例如,布局路径对于获取另一个布局内任意嵌套布局的偏移量(参见 bitOffset(PathElement...) )、快速获取与所选布局相对应的内存访问句柄(参见 varHandle(Class, PathElement...) )、选择另一个布局内的任意嵌套布局(请参阅 select(PathElement...) ,或将嵌套布局元素转换到另一个布局内(请参阅 map(UnaryOperator, PathElement...) )。

这样的 layout paths 可以使用此类中的方法以编程方式构建。例如,给定如上构造的taggedValues布局实例,我们可以获得first序列元素中名为value的成员布局的偏移量,以位为单位,如下所示:


long valueOffset = taggedValues.bitOffset(PathElement.sequenceElement(0),
                     PathElement.groupElement("value")); // yields 32
  
同样,我们可以选择名为value的成员布局,如下:

MemoryLayout value = taggedValues.select(PathElement.sequenceElement(),
                     PathElement.groupElement("value"));
  
并且,我们还可以将名为 value 的布局替换为其他布局,如下所示:

MemoryLayout taggedValuesWithHole = taggedValues.map(l -> MemoryLayout.paddingLayout(32),
                      PathElement.sequenceElement(), PathElement.groupElement("value"));
  
也就是说,上面的声明与下面的声明相同,更冗长:

MemoryLayout taggedValuesWithHole = MemoryLayout.sequenceLayout(5,
  MemoryLayout.structLayout(
    MemoryLayout.valueLayout(8, ByteOrder.nativeOrder()).withName("kind"),
    MemoryLayout.paddingLayout(32),
    MemoryLayout.paddingLayout(32)
));
  
布局路径可以包含一个或多个 free dimensions 。例如,遍历未指定序列元素的布局路径(即,使用 MemoryLayout.PathElement.sequenceElement() 方法获取其中一个路径组件)具有额外的自由维度,该维度必须在运行时绑定。当从布局获取内存访问 var 句柄时,这一点很重要,如以下代码所示:

VarHandle valueHandle = taggedValues.varHandle(int.class,
                        PathElement.sequenceElement(),
                        PathElement.groupElement("value"));
  
由于上例中构造的布局路径恰好具有一个自由维度(因为它没有指定应从封闭序列布局中选择名为 valuewhich 成布局),因此内存访问 var 句柄 valueHandle 将具有 additional long访问坐标。

具有自由尺寸的布局路径也可用于使用 bitOffset(PathElement...) byteOffsetHandle(PathElement...) 方法创建偏移计算方法句柄。同样,自由维度被转换为创建的方法句柄的long参数。通过在调用方法句柄时提供这些索引,方法句柄可用于计算不同索引处的序列元素的偏移量。例如:


MethodHandle offsetHandle = taggedValues.byteOffsetHandle(PathElement.sequenceElement(),
                             PathElement.groupElement("kind"));
long offset1 = (long) offsetHandle.invokeExact(1L); // 8
long offset2 = (long) offsetHandle.invokeExact(2L); // 16
  

布局属性

布局可以选择与一个或多个 attributes 相关联。布局属性形成 name/value 对,其中名称为 String ,值为 Constable 。布局属性最常见的形式是 layout name (请参阅 LAYOUT_NAME ),这是一个可以与内存布局关联的自定义名称,并且可以在构造 layout paths 时引用。
实现要求:
此接口的实现是不可变的、线程安全的和 value-based
  • 字段详细信息

  • 方法详情

    • describeConstable

      Optional <? extends DynamicConstantDesc <? extends MemoryLayout >> describeConstable()
      如果可以构造,则返回包含此布局的标称描述符的 Optional ;如果无法构造,则返回空的 Optional
      指定者:
      describeConstable 在接口 Constable
      返回:
      包含生成的标称描述符的 Optional ,如果无法构造,则为空 Optional
    • hasSize

      boolean hasSize()
      这个布局有指定的尺寸吗?如果布局是(或包含)未指定大小的序列布局,则布局没有指定的大小(请参阅 SequenceLayout.elementCount() )。值布局(请参阅 ValueLayout )和填充布局(请参阅 paddingLayout(long) always 具有指定的大小,因此在这些情况下此方法始终返回 true
      返回:
      true ,如果此布局具有指定的大小。
    • bitSize

      long bitSize()
      计算布局大小,以位为单位。
      返回:
      布局大小,以位为单位。
      抛出:
      UnsupportedOperationException - 如果布局是或包含未指定大小的序列布局(请参阅 SequenceLayout )。
    • byteSize

      default long byteSize()
      计算布局大小,以字节为单位。
      返回:
      布局大小,以字节为单位。
      抛出:
      UnsupportedOperationException - 如果布局是或包含未指定大小的序列布局(请参阅 SequenceLayout ),或者如果 bitSize() 不是 8 的倍数。
    • name

      Optional <String > name()
      返回与此布局关联的name(如果有)。

      这等效于以下代码:

      
        attribute(LAYOUT_NAME).map(String.class::cast);
        
      返回:
      布局name(如果有)。
      参见:
    • withName

      MemoryLayout  withName(String  name)
      创建一个具有所需布局 name 的新布局。

      这等效于以下代码:

      
        withAttribute(LAYOUT_NAME, name);
        
      参数:
      name - 布局名称。
      返回:
      一个与此布局相同的新布局,除了与其关联的 name 之外。
      参见:
    • bitAlignment

      long bitAlignment()
      返回与此布局关联的对齐约束,以位表示。布局对齐定义了 2 的幂 A,这是布局的逐位对齐。如果 A <= 8 那么 A/8 是正确指向此布局的任何指针必须对齐的字节数。因此:
      • A=8表示unaligned(通常意义上的),这在数据包中很常见。
      • A=64 表示字对齐(在 LP64 上),A=32 int 对齐,A=16 short 对齐等。
      • A=512 是 x86/SV ABI(对于 AVX-512 数据)要求的最严格对齐。
      如果未在此布局上设置显式对齐约束(请参阅 withBitAlignment(long) ),则此方法返回与此布局关联的 自然排列 约束(以位为单位)。
      返回:
      布局对齐约束,以位为单位。
    • byteAlignment

      default long byteAlignment()
      返回与此布局关联的对齐约束,以字节表示。布局对齐定义了 2 的幂 A,这是布局的字节对齐方式,其中 A 是正确指向此布局的任何指针必须对齐的字节数。因此:
      • A=1表示unaligned(通常意义上的),这在数据包中很常见。
      • A=8 表示字对齐(在 LP64 上),A=4 int 对齐,A=2 short 对齐等。
      • A=64 是 x86/SV ABI(用于 AVX-512 数据)要求的最严格对齐。
      如果未在此布局上设置显式对齐约束(请参阅 withBitAlignment(long) ),则此方法返回与此布局关联的 自然排列 约束(以字节为单位)。
      返回:
      布局对齐约束,以字节为单位。
      抛出:
      UnsupportedOperationException - 如果 bitAlignment() 不是 8 的倍数。
    • withBitAlignment

      MemoryLayout  withBitAlignment(long bitAlignment)
      创建一个具有所需对齐约束的新布局。
      参数:
      bitAlignment - 布局对齐约束,以位表示。
      返回:
      与此布局相同的新布局,除了与之关联的对齐约束。
      抛出:
      IllegalArgumentException - 如果 bitAlignment 不是 2 的幂,或者小于 8。
    • attribute

      Optional <Constable > attribute(String  name)
      返回具有给定名称的属性(如果存在)。
      参数:
      name - 属性名称
      返回:
      具有给定名称的属性(如果存在)。
    • withAttribute

      MemoryLayout  withAttribute(String  name, Constable  value)
      返回一个新的内存布局,它具有与此布局相同的属性,以及新指定的属性。如果此布局已包含具有相同名称的属性,则现有属性值将在返回的布局中被重写。
      参数:
      name - 属性名称。
      value - 属性值。
      返回:
      一个新的内存布局,它具有与此布局相同的属性,以及新指定的属性。
    • attributes

      Stream <String > attributes()
      返回与此布局关联的属性名称流。
      返回:
      与此布局关联的属性名称流。
    • bitOffset

      default long bitOffset(MemoryLayout.PathElement ... elements)
      计算由给定布局路径选择的布局的偏移量(以位为单位),其中该路径被认为植根于此布局。
      参数:
      elements - 布局路径元素。
      返回:
      elements 中的布局路径选择的布局的偏移量(以位为单位)。
      抛出:
      IllegalArgumentException - 如果布局路径未选择嵌套在此布局中的任何布局,或者布局路径包含一个或多个选择多个序列元素索引的路径元素(请参阅 MemoryLayout.PathElement.sequenceElement() MemoryLayout.PathElement.sequenceElement(long, long) )。
      UnsupportedOperationException - 如果布局路径遍历的布局之一具有未指定的大小。
      NullPointerException - 如果 elements == null ,或者 elements 中的任何元素是 null
    • bitOffsetHandle

      default MethodHandle  bitOffsetHandle(MemoryLayout.PathElement ... elements)
      创建一个方法句柄,可用于计算由给定布局路径选择的布局的偏移量(以位为单位),其中该路径被视为植根于此布局。

      返回的方法句柄的返回类型为 long ,并且具有与提供的布局路径中的自由维度一样多的 long 参数类型(请参阅 MemoryLayout.PathElement.sequenceElement() ,其中参数的顺序对应于路径元素的顺序。返回的方法handle 可用于计算类似于 bitOffset(PathElement...) 的布局偏移量,但仅在调用方法句柄时指定一些序列索引。

      方法句柄返回的最终偏移量计算如下:

      
        offset = c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n)
        
      其中 x_1x_2 、... x_n 是作为 long 参数提供的 dynamic 值,而 c_1c_2 、 ... c_mstatic 偏移常量和 s_0 , s_1 , ... s_nstatic 步幅常数,它们源自布局路径.
      参数:
      elements - 布局路径元素。
      返回:
      一个方法句柄,可用于计算给定布局路径元素指定的布局元素的位偏移,当提供缺少的序列元素索引时。
      抛出:
      IllegalArgumentException - 如果布局路径包含一个或多个选择多个序列元素索引的路径元素(请参阅 MemoryLayout.PathElement.sequenceElement(long, long) )。
      UnsupportedOperationException - 如果布局路径遍历的布局之一具有未指定的大小。
    • byteOffset

      default long byteOffset(MemoryLayout.PathElement ... elements)
      计算由给定布局路径选择的布局的偏移量(以字节为单位),其中该路径被认为是此布局的根。
      参数:
      elements - 布局路径元素。
      返回:
      elements 中的布局路径选择的布局的偏移量(以字节为单位)。
      抛出:
      IllegalArgumentException - 如果布局路径未选择嵌套在此布局中的任何布局,或者布局路径包含一个或多个选择多个序列元素索引的路径元素(请参阅 MemoryLayout.PathElement.sequenceElement() MemoryLayout.PathElement.sequenceElement(long, long) )。
      UnsupportedOperationException - 如果布局路径遍历的布局之一具有未指定的大小,或者如果 bitOffset(elements) 不是 8 的倍数。
      NullPointerException - 如果 elements == null ,或者 elements 中的任何元素是 null
    • byteOffsetHandle

      default MethodHandle  byteOffsetHandle(MemoryLayout.PathElement ... elements)
      创建一个方法句柄,可用于计算给定布局路径选择的布局的偏移量(以字节为单位),其中该路径被视为植根于此布局。

      返回的方法句柄的返回类型为 long ,并且具有与提供的布局路径中的自由维度一样多的 long 参数类型(请参阅 MemoryLayout.PathElement.sequenceElement() ,其中参数的顺序对应于路径元素的顺序。返回的方法handle 可用于计算类似于 byteOffset(PathElement...) 的布局偏移量,但仅在调用方法句柄时指定一些序列索引。

      方法句柄返回的最终偏移量计算如下:

      
        bitOffset = c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n)
        offset = bitOffset / 8
        
      其中 x_1x_2 、... x_n 是作为 long 参数提供的 dynamic 值,而 c_1c_2 、 ... c_mstatic 偏移常量和 s_0 , s_1 , ... s_nstatic 步幅常数,它们源自布局路径.

      如果计算的位偏移量不是 8 的倍数,则方法句柄将抛出 UnsupportedOperationException

      参数:
      elements - 布局路径元素。
      返回:
      一个方法句柄,可用于计算给定布局路径元素指定的布局元素的字节偏移量,当提供缺少的序列元素索引时。
      抛出:
      IllegalArgumentException - 如果布局路径包含一个或多个选择多个序列元素索引的路径元素(请参阅 MemoryLayout.PathElement.sequenceElement(long, long) )。
      UnsupportedOperationException - 如果布局路径遍历的布局之一具有未指定的大小。
    • varHandle

      default VarHandle  varHandle(Class <?> carrier, MemoryLayout.PathElement ... elements)
      创建一个内存访问变量句柄,可用于在给定布局路径选择的布局中取消引用内存,其中该路径被认为植根于此布局。

      返回的内存访问变量句柄访问的最终内存位置可以计算如下:

      
        address = base + offset
        
      其中,base表示由MemorySegment 访问坐标表示的基地址(参见MemorySegment.address() MemoryAddress.toRawLongValue() ),offset可以用以下形式表示:
      
        offset = c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n)
        
      其中 x_1x_2 、... x_n 是作为 long 参数提供的 dynamic 值,而 c_1c_2 、 ... c_mstatic 偏移常量和 s_0 , s_1 , ... s_nstatic 步幅常数,它们源自布局路径.
      API 注意:
      生成的 var 句柄将为该布局路径中包含的每个未指定的序列访问组件提供一个额外的 long 访问坐标。此外,生成的 var 句柄具有某些 访问模式限制 特征,这是所有内存访问 var 句柄所共有的。
      参数:
      carrier - var 句柄载体类型。
      elements - 布局路径元素。
      返回:
      一个 var 句柄,可用于在 elements 中的布局路径选择的(可能是嵌套的)布局处取消引用内存。
      抛出:
      UnsupportedOperationException - 如果布局路径具有一个或多个具有不兼容对齐约束的元素,或者如果布局路径遍历的布局之一具有未指定的大小。
      IllegalArgumentException - 如果载体不代表基本类型,如果载体是 voidboolean ,或者如果 elements 中的布局路径没有选择值布局(请参阅 ValueLayout ),或者如果所选值布局的大小符合与指定的运营商类型不匹配。
    • sliceHandle

      default MethodHandle  sliceHandle(MemoryLayout.PathElement ... elements)
      创建一个方法句柄,给定内存段,该方法句柄返回与给定布局路径选择的布局相对应的slice,其中该路径被视为以此布局为根。

      返回的方法句柄的返回类型为 MemorySegment ,具有 MemorySegment 参数作为表示要切片的段的前导参数,并且具有与提供的布局路径中的自由维度一样多的尾随 long 参数类型(请参阅 MemoryLayout.PathElement.sequenceElement() ,其中顺序参数的顺序对应于路径元素的顺序。返回的方法句柄可用于创建类似于使用 MemorySegment.asSlice(long, long) 的切片,但其中偏移参数是根据调用方法句柄时指定的索引动态计算的。

      返回段的偏移量计算如下:

      
        bitOffset = c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n)
        offset = bitOffset / 8
        
      其中 x_1x_2 、... x_n 是作为 long 参数提供的 dynamic 值,而 c_1c_2 、 ... c_mstatic 偏移常量和 s_0 , s_1 , ... s_nstatic 步幅常数,它们源自布局路径.

      计算偏移量后,返回的段就好像通过调用创建:

      
        segment.asSlice(offset, layout.byteSize());
        
      其中 segment 是要切片的段,其中 layout 是给定布局路径选择的布局,根据 select(PathElement...)

      如果计算的位偏移量不是 8 的倍数,则方法句柄将抛出 UnsupportedOperationException

      参数:
      elements - 布局路径元素。
      返回:
      一个方法句柄,可用于在给定段的情况下创建所选布局元素的切片。
      抛出:
      UnsupportedOperationException - 如果所选布局的大小(以位为单位)不是 8 的倍数。
    • select

      default MemoryLayout  select(MemoryLayout.PathElement ... elements)
      从以该布局为根的路径中选择布局。
      参数:
      elements - 布局路径元素。
      返回:
      elements 中的布局路径选择的布局。
      抛出:
      IllegalArgumentException - 如果布局路径未选择嵌套在此布局中的任何布局,或者布局路径包含选择一个或多个序列元素索引的一个或多个路径元素(请参阅 MemoryLayout.PathElement.sequenceElement(long) MemoryLayout.PathElement.sequenceElement(long, long) )。
    • map

      default MemoryLayout  map(UnaryOperator <MemoryLayout > op, MemoryLayout.PathElement ... elements)
      创建此布局的转换副本,其中从以该布局为根的路径中选择的布局被替换为应用给定操作的结果。
      参数:
      op - 要应用于所选布局的一元运算。
      elements - 布局路径元素。
      返回:
      新布局,其中 elements 中的布局路径选择的布局已被将 op 应用到所选布局的结果替换。
      抛出:
      IllegalArgumentException - 如果布局路径未选择嵌套在此布局中的任何布局,或者布局路径包含选择一个或多个序列元素索引的一个或多个路径元素(请参阅 MemoryLayout.PathElement.sequenceElement(long) MemoryLayout.PathElement.sequenceElement(long, long) )。
    • isPadding

      boolean isPadding()
      这是一个填充布局(例如从 paddingLayout(long) 创建的布局)吗?
      返回:
      true,如果此布局是填充布局。
    • equals

      boolean equals(Object  that)
      比较指定对象与此布局是否相等。当且仅当指定对象也是一个布局,并且它等于此布局时,才返回 true。如果两个布局属于同一类型、具有相同的大小、名称和对齐约束,则它们被视为相等。此外,根据布局类型,必须满足附加条件:
      重写:
      equals 在类 Object
      参数:
      that - 要与此布局比较是否相等的对象。
      返回:
      true 如果指定对象等于此布局。
      参见:
    • hashCode

      int hashCode()
      返回此布局的哈希码值。
      重写:
      hashCode 在类 Object
      返回:
      此布局的哈希码值。
      参见:
    • toString

      String  toString()
      返回此布局的字符串表示形式。
      重写:
      toString 在类 Object
      返回:
      此布局的字符串表示形式。
    • paddingLayout

      static MemoryLayout  paddingLayout(long size)
      创建具有给定大小的新填充布局。
      参数:
      size - 以位为单位的填充大小。
      返回:
      新的选择器布局。
      抛出:
      IllegalArgumentException - 如果size <= 0
    • valueLayout

      static ValueLayout  valueLayout(long size, ByteOrder  order)
      创建给定字节顺序和大小的值布局。
      参数:
      size - 值布局大小。
      order - 值布局的字节顺序。
      返回:
      新的值布局。
      抛出:
      IllegalArgumentException - 如果size <= 0
    • sequenceLayout

      static SequenceLayout  sequenceLayout(long elementCount, MemoryLayout  elementLayout)
      使用给定的元素布局和元素计数创建新的序列布局。
      参数:
      elementCount - 序列元素计数。
      elementLayout - 序列元素布局。
      返回:
      具有给定元素布局和大小的新序列布局。
      抛出:
      IllegalArgumentException - 如果elementCount < 0
    • sequenceLayout

      static SequenceLayout  sequenceLayout(MemoryLayout  elementLayout)
      创建一个新的序列布局,具有无限的元素计数和给定的元素布局。
      参数:
      elementLayout - 序列布局的元素布局。
      返回:
      具有给定元素布局的新序列布局。
    • structLayout

      static GroupLayout  structLayout(MemoryLayout ... elements)
      使用给定的成布局创建新的struct组布局。
      参数:
      elements - struct 组布局的成布局。
      返回:
      具有给定成布局的新struct组布局。
    • unionLayout

      static GroupLayout  unionLayout(MemoryLayout ... elements)
      使用给定的成布局创建新的union组布局。
      参数:
      elements - union 布局的成布局。
      返回:
      具有给定成布局的新union组布局。