150. Tackling the slicing allocator
Let’s consider the following three Java regular int arrays:
int[] arr1 = new int[]{1, 2, 3, 4, 5, 6};
int[] arr2 = new int[]{7, 8, 9};
int[] arr3 = new int[]{10, 11, 12, 13, 14};
Next, we want to allocate a memory segment to each of these arrays. A straightforward approach relies on Arena.allocateArray() introduced in Problem 143:
try (Arena arena = Arena.openConfined()) {
MemorySegment segment1
= arena.allocateArray(ValueLayout.JAVA_INT, arr1);
MemorySegment segment2
= arena.allocateArray(ValueLayout.JAVA_INT, arr2);
MemorySegment segment3
= arena.allocateArray(ValueLayout.JAVA_INT, arr3);
}
This approach allocates enough memory to accommodate each of the given arrays. But, sometimes, we want to allocate only a certain amount of memory. If this fixed amount is not enough then we want to tackle the problem differently. For this, we can rely on a java.lang.foreign.SegmentAllocator. Of course, there are many other scenarios when SegmentAllocator is useful, but for now, let’s tackle the following one.Let’s assume that we allow allocating a fixed size of 10 * 4 = 40 bytes. This is a bulk amount of memory that should be sliced between our three arrays. First, we allocate these 40 bytes as follows:
try (Arena arena = Arena.openConfined()) {
SegmentAllocator allocator =
SegmentAllocator.slicingAllocator(arena.allocate(10 * 4));
…
Next, we use the allocator to allocate a slice from these 40 bytes to each array. The first array (arr1) has 6 values, so the memory segment gets 6 * 4 = 24 bytes:
MemorySegment segment1 = allocator.allocateArray(
ValueLayout.JAVA_INT, arr1);
…
The segment allocator has available 40 – 24 = 16 more bytes. The second array (arr2) has 3 values, so the memory segment gets 3 * 4 = 12 bytes:
MemorySegment segment2 = allocator.allocateArray(
ValueLayout.JAVA_INT, arr2);
…
The segment allocator has available 16 – 12 = 4 more bytes. The third array (arr3) has 5 values, so it needs a memory segment of 5 * 4 = 20 bytes, but only 4 are available. This causes an IndexOutOfBoundsException and gives us the control to handle this corner case:
MemorySegment segment3 = allocator.allocateArray(
ValueLayout.JAVA_INT, arr3);
} catch (IndexOutOfBoundsException e) {
System.out.println(
“There is not enough memory to fit all data”);
// handle exception
}
A possible approach to avoid this IndexOutOfBoundsException may consist of giving memory to the segment allocator. In this case, we need to give it 16 more bytes, so we can express it as follows:
SegmentAllocator allocator = SegmentAllocator
.slicingAllocator(arena.allocate(10 * 4 + 4 * 4));
Of course, you don’t have to write 10 * 4 + 4 * 4. You can say 14 * 4, or just 56. Basically, our three arrays have 14 elements of 4 bytes each, and initially, we have covered only 10 of them. Next, we have increased the memory to cover the remaining 4 as well.