MemorySegment.ofByteBuffer(ByteBuffer.allocateDirect())

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Mon Feb 7 10:57:28 UTC 2022


Ah, that's a bug, thanks.

It should create a non-closeable global scope that keeps reference the 
byte buffer. We have that code to keep class loaders alive:

ResourceScopeImpl.heapScope(bb);

Maurizio

On 05/02/2022 11:27, Michael Zucchi wrote:
>
> 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