private static void writeToMemory(MemorySegment segment) throws InterruptedException {
    // Write values to native memory
    IO.print("Writing to memory:\t");
    for (int i = 0; i < 5; i++) {
        int value = (int) (Math.random() * 256);
        segment.setAtIndex(ValueLayout.JAVA_INT, i, value);
        IO.print("0x" + Integer.toHexString(value) + " ");
    }
    IO.println();
}

private static void readFromMemory(MemorySegment segment) throws InterruptedException {
    // Read values back from native memory
    IO.print("Read back from memory:\t");
    for (int i = 0; i < 5; i++) {
        int value = segment.getAtIndex(ValueLayout.JAVA_INT, i);
        IO.print("0x" + Integer.toHexString(value) + " ");
    }
    IO.println();
}

void main() throws Throwable {
    IO.println();
    IO.println("=== FFM API Demo: Memory Management ===");
    IO.println();

    // An arena controls the lifecycle of native memory segments,
    // providing both flexible allocation and timely deallocation.
    try (var arena = Arena.ofConfined()) {
        // Allocate memory for an array of 5 integers
        MemorySegment segment = arena.allocate(ValueLayout.JAVA_INT, 5);

        // Get the native address (pointer value)
        var address = segment.address();
        IO.println("Memory address: " + address + " - 0x" +
                Long.toHexString(segment.address()).toUpperCase());

        int loop = 0;
        while (loop < 5) {
            writeToMemory(segment);
            readFromMemory(segment);
            IO.println();
            Thread.sleep(500);
            loop++;
        }
    }
}