< prev index next >

src/java.base/share/classes/java/lang/foreign/Arena.java

Print this page

  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 
 26 package java.lang.foreign;
 27 
 28 import jdk.internal.foreign.MemorySessionImpl;
 29 import jdk.internal.javac.PreviewFeature;
 30 import jdk.internal.ref.CleanerFactory;
 31 
 32 import java.lang.foreign.MemorySegment.Scope;
 33 
 34 /**
 35  * An arena controls the lifecycle of native memory segments, providing both flexible allocation and timely deallocation.
 36  * <p>
 37  * An arena has a {@linkplain MemorySegment.Scope scope} - the <em>arena scope</em>. All the segments allocated
 38  * by the arena are associated with the arena scope. As such, the arena determines the temporal bounds
 39  * of all the memory segments allocated by it.
 40  * <p>
 41  * Moreover, an arena also determines whether access to memory segments allocated by it should be
 42  * {@linkplain MemorySegment#isAccessibleBy(Thread) restricted} to specific threads.
 43  * An arena is a {@link SegmentAllocator} and features several allocation methods that can be used by clients
 44  * to obtain native segments.
 45  * <p>
 46  * The simplest arena is the {@linkplain Arena#global() global arena}. The global arena
 47  * features an <em>unbounded lifetime</em>. As such, native segments allocated with the global arena are always
 48  * accessible and their backing regions of memory are never deallocated. Moreover, memory segments allocated with the
 49  * global arena can be {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} from any thread.

167  *         return slicingAllocator.allocate(byteSize, byteAlignment);
168  *     }
169  *
170  *     public MemorySegment.Scope scope() {
171  *         return arena.scope();
172  *     }
173  *
174  *     public void close() {
175  *         arena.close();
176  *     }
177  *
178  * }
179  * }
180  *
181  * In other words, a slicing arena provides a vastly more efficient and scalable allocation strategy, while still retaining
182  * the timely deallocation guarantee provided by the underlying confined arena:
183  *
184  * {@snippet lang = java:
185  * try (Arena slicingArena = new SlicingArena(1000)) {
186  *     for (int i = 0; i < 10; i++) {
187  *         MemorySegment s = slicingArena.allocateArray(JAVA_INT, 1, 2, 3, 4, 5);
188  *         ...
189  *     }
190  * } // all memory allocated is released here
191  * }
192  *
193  * @implSpec
194  * Implementations of this interface are thread-safe.
195  *
196  * @see MemorySegment
197  *
198  * @since 20
199  */
200 @PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
201 public interface Arena extends SegmentAllocator, AutoCloseable {
202 
203     /**
204      * Creates a new arena that is managed, automatically, by the garbage collector.
205      * Segments allocated with the returned arena can be
206      * {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by any thread.
207      * Calling {@link #close()} on the returned arena will result in an {@link UnsupportedOperationException}.
208      *
209      * @return a new arena that is managed, automatically, by the garbage collector.
210      */
211     static Arena ofAuto() {
212         return MemorySessionImpl.createImplicit(CleanerFactory.cleaner()).asArena();
213     }
214 
215     /**
216      * Obtains the global arena. Segments allocated with the global arena can be
217      * {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by any thread.
218      * Calling {@link #close()} on the returned arena will result in an {@link UnsupportedOperationException}.
219      *
220      * @return the global arena.
221      */
222     static Arena global() {
223         class Holder {
224             static final Arena GLOBAL = MemorySessionImpl.GLOBAL.asArena();
225         }
226         return Holder.GLOBAL;
227     }
228 
229     /**
230      * {@return a new confined arena} Segments allocated with the confined arena can be
231      * {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by the thread that created the arena,
232      * the arena's <em>owner thread</em>.
233      */
234     static Arena ofConfined() {
235         return MemorySessionImpl.createConfined(Thread.currentThread()).asArena();
236     }
237 
238     /**
239      * {@return a new shared arena} Segments allocated with the global arena can be
240      * {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by any thread.
241      */
242     static Arena ofShared() {
243         return MemorySessionImpl.createShared().asArena();
244     }

252      *
253      * @implSpec
254      * Implementations of this method must return a native segment featuring the requested size,
255      * and that is compatible with the provided alignment constraint. Furthermore, for any two segments
256      * {@code S1, S2} returned by this method, the following invariant must hold:
257      *
258      * {@snippet lang = java:
259      *     S1.asOverlappingSlice(S2).isEmpty() == true
260      * }
261      *
262      * @param byteSize the size (in bytes) of the off-heap region of memory backing the native memory segment.
263      * @param byteAlignment the alignment constraint (in bytes) of the off-heap region of memory backing the native memory segment.
264      * @return a new native memory segment.
265      * @throws IllegalArgumentException if {@code bytesSize < 0}, {@code byteAlignment <= 0}, or if {@code byteAlignment}
266      * is not a power of 2.
267      * @throws IllegalStateException if this arena has already been {@linkplain #close() closed}.
268      * @throws WrongThreadException if this arena is confined, and this method is called from a thread
269      * other than the arena's owner thread.
270      */
271     @Override
272     default MemorySegment allocate(long byteSize, long byteAlignment) {
273         return ((MemorySessionImpl)scope()).allocate(byteSize, byteAlignment);
274     }
275 
276     /**
277      * {@return the arena scope}
278      */
279     Scope scope();
280 
281     /**
282      * Closes this arena. If this method completes normally, the arena scope is no longer {@linkplain Scope#isAlive() alive},
283      * and all the memory segments associated with it can no longer be accessed. Furthermore, any off-heap region of memory backing the
284      * segments obtained from this arena are also released.
285      *
286      * @apiNote This operation is not idempotent; that is, closing an already closed arena <em>always</em> results in an
287      * exception being thrown. This reflects a deliberate design choice: failure to close an arena might reveal a bug
288      * in the underlying application logic.
289      *
290      * @implSpec If this method completes normally, then {@code this.scope().isAlive() == false}.
291      * Implementations are allowed to throw {@link UnsupportedOperationException} if an explicit close operation is
292      * not supported.
293      *
294      * @see Scope#isAlive()

  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 
 26 package java.lang.foreign;
 27 
 28 import jdk.internal.foreign.MemorySessionImpl;

 29 import jdk.internal.ref.CleanerFactory;
 30 
 31 import java.lang.foreign.MemorySegment.Scope;
 32 
 33 /**
 34  * An arena controls the lifecycle of native memory segments, providing both flexible allocation and timely deallocation.
 35  * <p>
 36  * An arena has a {@linkplain MemorySegment.Scope scope} - the <em>arena scope</em>. All the segments allocated
 37  * by the arena are associated with the arena scope. As such, the arena determines the temporal bounds
 38  * of all the memory segments allocated by it.
 39  * <p>
 40  * Moreover, an arena also determines whether access to memory segments allocated by it should be
 41  * {@linkplain MemorySegment#isAccessibleBy(Thread) restricted} to specific threads.
 42  * An arena is a {@link SegmentAllocator} and features several allocation methods that can be used by clients
 43  * to obtain native segments.
 44  * <p>
 45  * The simplest arena is the {@linkplain Arena#global() global arena}. The global arena
 46  * features an <em>unbounded lifetime</em>. As such, native segments allocated with the global arena are always
 47  * accessible and their backing regions of memory are never deallocated. Moreover, memory segments allocated with the
 48  * global arena can be {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} from any thread.

166  *         return slicingAllocator.allocate(byteSize, byteAlignment);
167  *     }
168  *
169  *     public MemorySegment.Scope scope() {
170  *         return arena.scope();
171  *     }
172  *
173  *     public void close() {
174  *         arena.close();
175  *     }
176  *
177  * }
178  * }
179  *
180  * In other words, a slicing arena provides a vastly more efficient and scalable allocation strategy, while still retaining
181  * the timely deallocation guarantee provided by the underlying confined arena:
182  *
183  * {@snippet lang = java:
184  * try (Arena slicingArena = new SlicingArena(1000)) {
185  *     for (int i = 0; i < 10; i++) {
186  *         MemorySegment s = slicingArena.allocateFrom(JAVA_INT, 1, 2, 3, 4, 5);
187  *         ...
188  *     }
189  * } // all memory allocated is released here
190  * }
191  *
192  * @implSpec
193  * Implementations of this interface are thread-safe.
194  *
195  * @see MemorySegment
196  *
197  * @since 22
198  */

199 public interface Arena extends SegmentAllocator, AutoCloseable {
200 
201     /**
202      * Creates a new arena that is managed, automatically, by the garbage collector.
203      * Segments allocated with the returned arena can be
204      * {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by any thread.
205      * Calling {@link #close()} on the returned arena will result in an {@link UnsupportedOperationException}.
206      *
207      * @return a new arena that is managed, automatically, by the garbage collector.
208      */
209     static Arena ofAuto() {
210         return MemorySessionImpl.createImplicit(CleanerFactory.cleaner()).asArena();
211     }
212 
213     /**
214      * Obtains the global arena. Segments allocated with the global arena can be
215      * {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by any thread.
216      * Calling {@link #close()} on the returned arena will result in an {@link UnsupportedOperationException}.
217      *
218      * @return the global arena.
219      */
220     static Arena global() {
221         class Holder {
222             static final Arena GLOBAL = MemorySessionImpl.createGlobal().asArena();
223         }
224         return Holder.GLOBAL;
225     }
226 
227     /**
228      * {@return a new confined arena} Segments allocated with the confined arena can be
229      * {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by the thread that created the arena,
230      * the arena's <em>owner thread</em>.
231      */
232     static Arena ofConfined() {
233         return MemorySessionImpl.createConfined(Thread.currentThread()).asArena();
234     }
235 
236     /**
237      * {@return a new shared arena} Segments allocated with the global arena can be
238      * {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by any thread.
239      */
240     static Arena ofShared() {
241         return MemorySessionImpl.createShared().asArena();
242     }

250      *
251      * @implSpec
252      * Implementations of this method must return a native segment featuring the requested size,
253      * and that is compatible with the provided alignment constraint. Furthermore, for any two segments
254      * {@code S1, S2} returned by this method, the following invariant must hold:
255      *
256      * {@snippet lang = java:
257      *     S1.asOverlappingSlice(S2).isEmpty() == true
258      * }
259      *
260      * @param byteSize the size (in bytes) of the off-heap region of memory backing the native memory segment.
261      * @param byteAlignment the alignment constraint (in bytes) of the off-heap region of memory backing the native memory segment.
262      * @return a new native memory segment.
263      * @throws IllegalArgumentException if {@code bytesSize < 0}, {@code byteAlignment <= 0}, or if {@code byteAlignment}
264      * is not a power of 2.
265      * @throws IllegalStateException if this arena has already been {@linkplain #close() closed}.
266      * @throws WrongThreadException if this arena is confined, and this method is called from a thread
267      * other than the arena's owner thread.
268      */
269     @Override
270     MemorySegment allocate(long byteSize, long byteAlignment);


271 
272     /**
273      * {@return the arena scope}
274      */
275     Scope scope();
276 
277     /**
278      * Closes this arena. If this method completes normally, the arena scope is no longer {@linkplain Scope#isAlive() alive},
279      * and all the memory segments associated with it can no longer be accessed. Furthermore, any off-heap region of memory backing the
280      * segments obtained from this arena are also released.
281      *
282      * @apiNote This operation is not idempotent; that is, closing an already closed arena <em>always</em> results in an
283      * exception being thrown. This reflects a deliberate design choice: failure to close an arena might reveal a bug
284      * in the underlying application logic.
285      *
286      * @implSpec If this method completes normally, then {@code this.scope().isAlive() == false}.
287      * Implementations are allowed to throw {@link UnsupportedOperationException} if an explicit close operation is
288      * not supported.
289      *
290      * @see Scope#isAlive()
< prev index next >