The changes described here might impact some clients; more specifically, the biggest incompatibility is in the behavior of the memory access var handle; they used to accept a `MemoryAddress` coordinate, but that has changed in this update to a `MemorySegment` coordinate. Other areas of the API, remained largely unchanged, despite getting some improvements and added functionalities.
That said, since the API is an incubating API, and not available by default (unless the `--add-modules` flag is passed to the `java` launcher), these changes should not affect a significant portion of users.The changes described here might impact some clients; more specifically, the biggest incompatibility is in the behavior of the memory access var handle; they used to accept a `MemoryAddress` coordinate, but that has changed in this update to a `MemorySegment` coordinate. Other areas of the API, remained largely unchanged, despite getting some improvements and added functionalities. That said, since the API is an incubating API, and not available by default (unless the `--add-modules` flag is passed to the `java` launcher), these changes should not affect a significant portion of users.
This CSR refers to the third iteration of the Foreign Memory Access (an incubating Java API) originally targeted for Java 14 (and later re-incubated in 15), with the goal of refining some of the API rough edges, as well as addressing the feedback received so far from developers.
Real-world use of the Foreign Memory Access API revealed some remaining usability issues, listed below:
- The API's bias towards confinement is still too prominent, despite the addition (in 15) of an API point to cooperatively change thread ownership of a given segment (serial confinement); the main issue is that, even with the new API, it is still not possible to close a memory segment from a thread other than the owner thread, and that makes memory segment hard to use with certain API idioms
- While deterministic deallocation is one of the core foundations of the Foreign Memory Access API, users have expressed interest in having the ability to optionally register segments against a
Cleanerinstance, so that segment deallocation could be guaranteed regardless of whether an explicit call to
- The distinction between checked and unchecked memory addresses is too subtle. Checked addresses have a reference to the owning segment, and can be safely dereferenced, whereas unchecked addresses can't. This leads to verbosity in clients attempting to dereference a
MemoryAddressinstance, as the client has first to query if a segment is available, and then act accordingly.
- Forcing developers to exclusively use
VarHandlewhen it comes to dereference memory is a bit too much; there are cases where the expressive power of var handles come in handy (e.g. in concurrent contexts, when fencing is required, or when structural access is needed), but in simpler cases it would be nice to have a ready-made collections of dereference API points which can be used in a type-safe way.
- While a memory address and a memory segment generally represent separate concepts, it is possible to go from the latter to the former (e.g. by calling the
MemorySegment::baseAddressmethod). Our experiments with the
jextracttool revealed that the need for this explicit conversion has often a pretty big impact in the verbosity of clients interacting with the native bindings generated by jextract.
Here we describe the main ideas behind the API changes brought forward in this CSR:
- First, the notion of shared memory segment is introduced. A shared memory segment is created by invoking the
MemorySegment::sharemethod that returns a new memory segment instance, which is backed by the same memory region, and has no owner thread. This means that the segment will be effectively accessible (and closeable) from multiple threads (possibly in a concurrent fashion). The safety promises of the Foreign Memory Access API are preserved by a sophisticated lock-free synchronization scheme which relies on thread-local handshakes (see JEP 312).
- A new method is added to memory segments,
MemorySegment::registerCleaner(Cleaner)that returns a new segment instance, which is backed by the same memory region, and supports implicit deallocation.
- Memory access var handles now use memory segments as the basic dereference unit. That is, the most basic memory access var handle accepts two coordinates: the segment to be dereferenced and the offset within the segment at which the dereference should occur. All other, structural memory access var handles can be composed from this basic one. As a result,
MemoryAddresshas reverted back to being a dumb carrier for an object/offset unsafe addressing coordinate pair. That is, there is no way to go from an address back to a segment (except unsafely via
MemoryAddress::asSegmentRestrictedbut that creates a new segment).
- A new class, namely
MemoryAccessis introduced. This class contains several dereference methods to get and set values in memory, with different Java carriers. There are different access modes supported: a basic one which simply takes a memory segment and dereferences it at its base address; other, more sophisticated, modes allows a byte offset or a logical index to be passed as well, to support common array-like access idioms.
- To better capture the commonality between a memory segment and a memory address a new interface, namely
Addressablehas been introduced. This interface describes entities that can be mapped into a memory address. This interface is implemented, trivially, by
MemoryAddressand also by
MemorySegment(a memory segment can always be projected to its base address). We plan, with subsequent JEPs (e.g. JEP 389) to add more implementations of this interface.
- The hierarchy of interface
MappedMemorySegment <: MemorySegmentposes issues when it comes to
VarHandleinvocations; since now the memory access var handle take a
MemorySegmentaccess coordinate, calling such var handles with a
MappedMemorySegmentcoordinate will result in a non-exact var handle call, thus greatly degrading performances; we have decided to drop the
MappedMemorySegmentinterface and instead introduce an helper class, namely
MappedMemorySegments, which contains static methods which provide the same functionality as what was provided by
Here are some useful links which should help in navigating through the changes in the API.
In addition, a specdiff of the changes as of November 9th 2020 has been attached to this CSR.