Module java.base

Interface Arena

所有超级接口:
AutoCloseable, SegmentAllocator预览

public interface Arena extends SegmentAllocatorPREVIEW, AutoCloseable
Arena 是Java平台的预览API。
仅当启用预览功能时,程序才能使用Arena
预览功能可能会在将来的版本中被移除,或升级为Java平台的永久功能。
一个arena控制本机内存段的生命周期,提供灵活的分配和及时的释放。

一个arena具有一个scope预览 - arena scope。由arena分配的所有段都与arena scope相关联。因此,arena确定了由其分配的所有内存段的时间范围。

此外,arena还确定由其分配的内存段是否应该对特定线程受限制预览。arena是一个SegmentAllocator预览,具有几种分配方法,客户端可以使用这些方法来获取本机段。

最简单的arena是全局arena。全局arena具有无限的生命周期。因此,使用全局arena分配的本机段始终可访问,并且它们的内存后备区域永远不会被释放。此外,使用全局arena分配的内存段可以从任何线程访问预览

 MemorySegment segment = Arena.global().allocate(100, 1);
 ...
 // 段永远不会被释放!

另外,客户端可以获取一个自动arena,即由垃圾回收器自动管理生命周期的arena。因此,使用自动arena分配的内存段的内存后备区域将在自动arena(及其分配的所有段)变为不可达后的某个不确定时间之后被释放,如下所示:

 MemorySegment segment = Arena.ofAuto().allocate(100, 1);
 ...
 segment = null; // 在此点之后,段区域变为可释放
使用自动arena分配的内存段也可以从任何线程访问预览

客户端通常希望控制内存段的释放时间,而不是将释放时间留给Java运行时。两种类型的arena支持这一点,即受限制共享 arena。它们都具有手动管理的有界生命周期。例如,受限制arena的生命周期从创建受限制arena开始,到关闭受限制arena结束。因此,使用受限制arena分配的内存段在关闭受限制arena时被释放。在这种情况下,使用受限制arena分配的所有段都将无效,并且对这些段进行的后续访问操作将导致IllegalStateException异常:

 MemorySegment segment = null;
 try (Arena arena = Arena.ofConfined()) {
     segment = arena.allocate(100);
     ...
 } // 段区域在此处被释放
 segment.get(ValueLayout.JAVA_BYTE, 0); // 抛出IllegalStateException
使用受限制arena分配的内存段只能被创建arena的线程访问(和关闭)。如果需要从多个线程访问内存段,则客户端可以选择在共享arena中分配段。

各种arena的特征总结在以下表中:

Arena特征
类型 有界生命周期 可显式关闭 可从多个线程访问
全局
自动
受限制
共享

安全性和线程限制

Arenas提供强大的时间安全保证:由arena分配的内存段在arena关闭后无法访问。提供此保证的成本取决于可以访问由arena分配的内存段的线程数量。例如,如果一个arena总是由一个线程创建和关闭,并且由该相同线程始终访问由arena分配的内存段,则确保正确性是微不足道的。

相反,如果一个arena分配的段可以被多个线程访问,或者如果可以由非访问线程关闭arena,则确保正确性就复杂得多。例如,使用arena分配的段可能在另一个线程尝试同时关闭arena的情况下被访问。为了提供强大的时间安全保证,而不强迫每个客户端,甚至是简单的客户端,承担性能影响,arenas被分为线程限制 arenas和共享 arenas。

受限制的arenas支持强大的线程限制保证。创建时,它们被分配一个所有者线程,通常是启动创建操作的线程。受限制arena创建的段只能由所有者线程访问预览。此外,任何尝试从非所有者线程关闭受限制arena的操作将导致WrongThreadException异常。

另一方面,共享arenas没有所有者线程。共享arena创建的段可以被任何线程访问预览。当多个线程需要同时访问相同的内存段时(例如在并行处理的情况下),这可能很有用。此外,任何线程都可以关闭共享arena。

自定义arenas

客户端可以定义自定义arenas来实现更高效的分配策略,或者更好地控制arena何时(以及由谁)可以关闭。例如,以下代码定义了一个切片arena,其行为类似于受限制arena(即,单线程访问),但在内部使用切片分配器预览来响应分配请求。当切片arena关闭时,底层受限制arena也将关闭;这将使所有使用切片arena分配的段无效(因为切片arena的范围与底层受限制arena的范围相同):
class SlicingArena implements Arena {
    final Arena arena = Arena.ofConfined();
    final SegmentAllocator slicingAllocator;

    SlicingArena(long size) {
        slicingAllocator = SegmentAllocator.slicingAllocator(arena.allocate(size));
    }

    public MemorySegment allocate(long byteSize, long byteAlignment) {
        return slicingAllocator.allocate(byteSize, byteAlignment);
    }

    public MemorySegment.Scope scope() {
        return arena.scope();
    }

    public void close() {
        arena.close();
    }

}
换句话说,切片arena提供了一种更高效和可扩展的分配策略,同时仍保留底层受限制arena提供的及时释放保证:
try (Arena slicingArena = new SlicingArena(1000)) {
    for (int i = 0; i < 10; i++) {
        MemorySegment s = slicingArena.allocateArray(JAVA_INT, 1, 2, 3, 4, 5);
        ...
    }
} // 所有分配的内存在此释放
实现要求:
此接口的实现是线程安全的。
自:
20
另请参阅:
  • Method Details

    • ofAuto

      static ArenaPREVIEW ofAuto()
      创建一个由垃圾回收器自动管理的新区域。使用返回的区域分配的段可以被任何线程访问预览。在返回的区域上调用close()将导致UnsupportedOperationException
      返回:
      一个由垃圾回收器自动管理的新区域。
    • global

      static ArenaPREVIEW global()
      获取全局区域。使用全局区域分配的段可以被任何线程访问预览。在返回的区域上调用close()将导致UnsupportedOperationException
      返回:
      全局区域。
    • ofConfined

      static ArenaPREVIEW ofConfined()
      返回一个新的受限区域。使用受限区域分配的段只能被创建区域的线程,即区域的所有者线程 访问预览
      返回:
      一个新的受限区域
    • ofShared

      static ArenaPREVIEW ofShared()
      返回一个新的共享区域。使用全局区域分配的段可以被任何线程访问预览
      返回:
      一个新的共享区域
    • allocate

      default MemorySegmentPREVIEW allocate(long byteSize, long byteAlignment)
      返回具有给定大小(以字节为单位)和对齐约束(以字节为单位)的本机内存段。返回的段与此区域范围相关联。段的address预览是分配的用于支持段的堆外内存区域的起始地址,并且根据提供的对齐约束对齐。
      指定者:
      allocate 在接口 SegmentAllocator预览
      实现要求:
      此方法的实现必须返回具有请求大小并与提供的对齐约束兼容的本机段。此外,对于此方法返回的任何两个段S1, S2,必须满足以下不变式:
          S1.asOverlappingSlice(S2).isEmpty() == true
      
      参数:
      byteSize - 本机内存段支持的堆外内存区域的大小(以字节为单位)。
      byteAlignment - 本机内存段支持的堆外内存区域的对齐约束(以字节为单位)。
      返回:
      一个新的本机内存段。
      抛出:
      IllegalArgumentException - 如果bytesSize < 0byteAlignment <= 0,或者byteAlignment不是2的幂。
      IllegalStateException - 如果此区域已经被关闭
      WrongThreadException - 如果此区域是受限的,并且从非区域所有者线程调用此方法。
    • scope

      返回区域范围。
      返回:
      区域范围
    • close

      void close()
      关闭此区域。如果此方法正常完成,则区域范围不再存活预览,并且与之关联的所有内存段将不再可访问。此外,从此区域获取的所有内存段的堆外内存区域也将被释放。
      指定者:
      close 在接口 AutoCloseable
      API 注意:
      此操作不是幂等的;也就是说,关闭已经关闭的区域总是会导致抛出异常。这反映了一个故意的设计选择:未能关闭区域可能会揭示底层应用程序逻辑中的错误。
      实现要求:
      如果此方法正常完成,则this.scope().isAlive() == false。如果不支持显式关闭操作,实现可以抛出UnsupportedOperationException
      抛出:
      IllegalStateException - 如果区域已经被关闭。
      IllegalStateException - 如果与此区域关联的段正在被并发访问,例如通过downcall方法句柄预览
      WrongThreadException - 如果此区域是受限的,并且从非区域所有者线程调用此方法。
      UnsupportedOperationException - 如果无法显式关闭此区域。
      另请参阅: