MemorySegment.ofByteBuffer(ByteBuffer.allocateDirect())

Michael Zucchi notzed at gmail.com
Sat Feb 5 11:27:03 UTC 2022


Evening,

I'm seeing a direct ByteBuffer being freed while still used by a 
MemorySegment.ofByteBuffer().   I'm apparently using foreign-jextract @ 
commit 6c3e90789b1a6590894f09c2027a7fcf9e23af06 (Fri Jan 28 11:01:26 
2022) but it hasn't changed for months.

The docs for ofByteBuffer() explicitly state the backing buffer is 
referenced.

     /**
      * Creates a new buffer memory segment that models the memory 
associated with the given byte
      * buffer. The segment starts relative to the buffer's position 
(inclusive)
      * and ends relative to the buffer's limit (exclusive).
      * <p>
      * If the buffer is {@link ByteBuffer#isReadOnly() read-only}, the 
resulting segment will also be
      * {@link ByteBuffer#isReadOnly() read-only}. The scope associated 
with this segment can either be the
      * {@linkplain ResourceScope#globalScope() global} resource scope, 
in case the buffer has been created independently,
      * or some other resource scope, in case the buffer has been 
obtained using {@link #asByteBuffer()}.
      * <p>
      * The resulting memory segment keeps a reference to the backing 
buffer, keeping it <em>reachable</em>.
      *
      * @param bb the byte buffer backing the buffer memory segment.
      * @return a new buffer memory segment.
      */

But I don't see how it could be looking at 
AbstractMemorySegmentImpl.ofBuffer(), it just creates the segment using 
(long, long, int, scope)

     public static AbstractMemorySegmentImpl ofBuffer(ByteBuffer bb) {
...
             return new NativeMemorySegmentImpl(bbAddress + pos, size, 
modes, bufferScope);
...
     }

For what it's worth this is the code i'm using.  IntArray is just a thin 
wrapper over MemorySegment.

     IntArray loadSPIRV(String name) throws IOException {
         try (InputStream is = TestVulkan.class.getResourceAsStream(name)) {
             ByteBuffer bb = 
ByteBuffer.allocateDirect(8192).order(ByteOrder.nativeOrder());
             int length = Channels.newChannel(is).read(bb);

             bb.position(0);
             bb.limit(length);

             return IntArray.create(MemorySegment.ofByteBuffer(bb));
         }
     }
     IntArray mandelbrot_cs;

     void demo() throws Exception {
         mandelbrot_cs = loadSPIRV("mandelbrot.bin");

         ... at some point later and before i use it it's junk, vulkan 
crashes  ...
     }

If I keep a hard reference to 'bb' then it works fine indicating it's 
probably getting gc'd otherwise.

     ByteBuffer bb;

     IntArray loadSPIRV(String name) throws IOException {
...
             bb.position(0);
             bb.limit(length);

             this.bb = bb;
...
     }

This version of loadSPIRV works fine:

     IntArray loadSPIRV(String name) throws IOException {
         try (InputStream is = TestVulkan.class.getResourceAsStream(name)) {
             MemorySegment seg = 
((SegmentAllocator)scope).allocateArray(Memory.INT, 2048);
             int length = Channels.newChannel(is).read(seg.asByteBuffer());

             return IntArray.create(seg.asSlice(0, length));
         }
     }


Regards,
  !Z


More information about the panama-dev mailing list