I'm currently investigating switching from memory mapped files using the ByteBuffer/DoubleBuffer API to the newly introduced project Panama API.
Since MemorySegment has the .asByteBuffer method, I first tried to use it as a drop-in replacement and port the rest of the software from there.
Unfortunately, i'm unable to get a simple test to work, because when reading from the generated byte buffer, I'm getting different results than from the memory segment and the original data.
I first tried to use an Arena instead of a mapped file. Minimal failing example is down below (Java 21 with preview features):
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.SegmentAllocator;
import java.lang.foreign.ValueLayout;
import java.lang.foreign.ValueLayout.OfDouble;
import java.nio.ByteBuffer;
import java.nio.DoubleBuffer;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
public class MemorySegmentTest {
@Test
void testLoad() {
try (final Arena arena = Arena.ofAuto()) {
final MemorySegment segment = arena.allocate(Double.BYTES * 10,
OfDouble.JAVA_DOUBLE.byteAlignment());
SegmentAllocator alloc = SegmentAllocator.slicingAllocator(segment);
final double[] stored = new double[]{15.345, 7.231, 123.34234};
final MemorySegment allocated = alloc.allocateArray(ValueLayout.JAVA_DOUBLE, stored);
// ok
Assertions.assertEquals(stored[0], allocated.getAtIndex(ValueLayout.JAVA_DOUBLE, 0));
final ByteBuffer byteBuffer = allocated.asByteBuffer();
final double fromByteBuffer = byteBuffer.getDouble(0);
Assertions.assertEquals(stored[0], fromByteBuffer); // fails
final DoubleBuffer doubleBuffer = allocated.asByteBuffer().asDoubleBuffer();
final double fromDoubleBuffer = doubleBuffer.get(0);
Assertions.assertEquals(stored[0], fromDoubleBuffer); // fails
}
}
}
Replacing the arena with a mapped file like this also does not work.
FileChannel channel = FileChannel.open(file.toPath(), StandardOpenOption.READ,
StandardOpenOption.WRITE, StandardOpenOption.CREATE);
final MemorySegment currentSegment = channel.map(MapMode.READ_WRITE, 0, capacity,
Arena.ofAuto());
Due to the error message: org.opentest4j.AssertionFailedError: expected: <15.345> but was: <2.954938175610712E237> i think it's something to do with the byte aligment or so, but i'm not an expert in that.
Any ideas what might be wrong?
It looks like you may have a machine with
ByteOrder.nativeOrder() == LITTLE_ENDIAN. However the documentation of MemorySegment.asByteBuffer reports thatbyteBufferwill have byte orderBIG_ENDIAN.In order for your memory access when to work you need to use consistent byte order to your chosen layout, in this case:
Also, you must get DoubleBuffer with same byte order, so create
doubleBuffervia byteBuffer:Whatever layout/byte order you need to choose will of course need to be consistent with the apps that generate the file format you are mapping in your Java app.
This JDK22 based example demonstrates:
On my LITTLE_ENDIAN machine prints: