On Mon, 31 Aug 2026 13:37:15 GMT, Per Minborg <[email protected]> wrote:

>> ## Summary
>> 
>> This PR proposes to introduce a pooled confined arena as an optimization for 
>> `Arena.ofConfined()`, where small native allocations can be served from a 
>> reusable per-thread memory pool or a local arena pool instead of calling the 
>> regular native allocator for every short-lived arena. The arena remains 
>> confined to its owner thread and is still closed normally, but its backing 
>> storage can be reset and reused when the arena closes. The feature requires 
>> no API changes.
>> 
>> ### Outline
>> 
>> Platform threads: There are up to eight (four by default) lazily allocated 
>> pools per Thread, encoded in `Thread.FieldHolder.confinedMemoryPool`.
>> Virtual threads: Works in the same way but uses its _carrier thread's _ 
>> cache instead.
>> 
>> Pooled memory is zeroed out upon _closing_ an Arena to minimize data 
>> visibility between reuse. This means the data is visible only within a TWR 
>> block, and never outside it.
>> 
>> A confined arena has access to one, two, four, or eight (four by default) 
>> platform/carrier thread pools, each of size 64 bytes by default.  The pool 
>> sizes are configurable via an internal unsupported system property and can 
>> be 8 bytes .. 1 MiB. Pooling can also be turned off completely by setting 
>> the pool properties to negative values. As there can be up to eight pools 
>> per thread, nested confined arenas backed by thread-cached pools are 
>> supported (i.e., up to eight nested arenas).
>> 
>> ## Static Analysis
>> 
>> An extensive static corpus analysis of third-party libraries and the JDK 
>> itself has been conducted with respect to `Area.ofConfined()` usage, 
>> revealing that confined arenas were used _only_ in TWR blocks and _never_ in 
>> an unstructured way. The static analysis further revealed that in most 
>> cases, only a small amount of native memory was ever allocated, usually less 
>> than 32 bytes, and in many cases, 8 bytes or less. This usage pattern lends 
>> itself well to pooling. 
>> 
>> ## Dynamic Analysis
>> 
>> A dynamic statistical analysis of actual runs was also made, where various 
>> properties of confined arenas were recorded and summarized during a complete 
>> tier1 test run. While a tier1 run is not necessarily representative of a 
>> typical application workload, it provided some interesting results:
>> 
>> The run produced 93 per-process histogram blocks and 788,773,092 closed 
>> confined arenas. The result is dominated by arenas with no native allocation 
>> at all: 375,934,768 arenas (47.661%) are in the zero-byte bucket. Counting 
>> arenas up to 63 bytes covers 99.997% of a...
>
> Per Minborg has updated the pull request incrementally with three additional 
> commits since the last revision:
> 
>  - Remove unused method
>  - Pin virtual threads
>  - Update benchmarks

src/java.base/share/classes/jdk/internal/foreign/ArenaImpl.java line 112:

> 110:                     pool = ConfinedSegmentPool.acquire(session.owner);
> 111:                     if (pool == 0) {
> 112:                         pool = 
> ConfinedSegmentPool.allocateLocal(session.owner);

These methods only work with the "current thread" so I'm wondering why the 
Thread parameter is needed. Each of the methods has an assert to check that the 
parameter is the current thread.

-------------

PR Review Comment: https://git.openjdk.org/jdk/pull/31365#discussion_r3896072472

Reply via email to