MemorySegment.ofByteBuffer(ByteBuffer.allocateDirect())

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Mon Feb 7 12:19:34 UTC 2022


On 07/02/2022 10:57, Maurizio Cimadamore wrote:
> Ah, that's a bug, thanks.

Filed: https://bugs.openjdk.java.net/browse/JDK-8281334

Maurizio

>
> 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