Access Native Data Types
Describe a C structure with a MemoryLayout
Getting access to structured data with only basic operations can produce complicated code difficult to maintain. An elegant solution is to use memory layouts that are more efficiently to initialize and can access more complex native data types such as C structures.
For example, let's consider a C structure that describes a fraction:
In Java, you can choose to represent this structure with a MemoryLayout:
The method MemoryLayout.structLayout(MemoryLayout...) returns a StructLayout object.
The structure layout contains two JAVA_INT value layouts, one for the numerator and another one for denominator.
The predefined value ValueLayout.JAVA_INT contains information about how many bytes a Java int value requires.
Let's calculate the addition between two fractions using the custom MemoryLayout fractionLayout. Start with instantiating an arena to manage off-heap memory and allocating memory for two fractions and one for result fraction:
Next, you need two VarHandles with access to the memory address offsets:
A VarHandle is a dynamically strongly typed reference to a variable or to a parameterized family of variables, including static fields, non-static fields, array elements, or components of an off-heap data structure.
The method call PathElement.groupElement("numerator") retrieves a memory layout named numerator.
The following step sets the values of the fractions by calling VarHandle.set(java.lang.Object...):
In the numeratorHandle.set(fraction1, 0, 1) example, the set method uses three arguments:
fraction1is the memory segment in which to set the value.0is the base offset and enables you to express complex access operations by injecting additional offset computation into theVarHandle.1is the actual value to set.
Similarly, you can get access to values with VarHandle.get(java.lang.Object...) and finally calculate the result:
You can check the result of your work by pasting the above snippet in a jshell session and obtain:
While this example adds the value of two fractions, let's see how you can handle addition of each two fractions in an array of such elements.
Slicing Allocators
There are two options to scale the previous example and perform addition of each two fractions in an array with a custom data type:
- Use a slicing allocator that returns a segment allocator. The
SegmentAllocatorresponds to allocation requests by returning consecutive contiguous regions of memory, or slices, obtained from an existing memory segment. - Obtain a slice of a memory segment of any location within a memory segment with the method
MemorySegment.asSlice.
Let's start with storing twenty fractions in a SequenceLayout:
Next, you can allocate memory for the twenty fractions using a SegmentAllocator.slicingAllocator(MemorySegment) :
With the SegmentAllocator you can obtain consecutive slices from a given segment and further allocate an array of integers in each slice.
In case of our example, a fraction is allocated in each slice.
Finally, complete the logic of the example by adding each two fractions:
Paste the above code in a jshell session and check if the results match:
Slice a Memory Segment
A slicing allocator returns a slice and is useful when working with consecutive contiguous regions of memory. The slice's starting address is right after the end of the last slice that the slicing allocator returned.
In case you want to obtain a slice of a memory segment of any location within a memory segment and of any size, you can call MemorySegment.asSlice(long,long).
Warning:
MemorySegment.asSlice(long,long)will return a slice of aMemorySegmentas long as the slice's size stays within the spatial bounds of the original memory segment.
Let's reuse the previous MemoryLayout for fractions and obtain slices of a memory segment:
As multiple threads can work in parallel to access each of the slices, the memory segment has to be accessible to them. You can achieve this by associating the memory segment with a shared arena.
Copy and paste the snippet below to try the full example in a jshell session:
Last update: December 28, 2024