[PATCH] RFR Bug-pending: Enable Hotspot to Track Native Memory Usage for Direct Byte Buffers

Adam Farley8 adam.farley at uk.ibm.com
Mon Feb 19 13:08:01 UTC 2018


Hi Paul,

> Hi Adam,
>
> From reading the thread i cannot tell if this is part of a wider 
solution including some yet to be proposed HotSpot changes.

The wider solution would need to include some Hotspot changes, yes.
I'm proposing raising a bug, committing the code we have here to
"set the stage", and then we can invest more time&energy later
if the concept goes down well and the community agrees to pursue
the full solution.

As an aside, I tried submitting a big code set (including hotspot
changes) months ago, and I'm *still* struggling to find someone to
commit the thing, so I figured I'd try a more gradual, staged approach
this time.

>
> As is i would be resistant to adding such standalone internal wrapper 
methods to Unsafe that have no apparent benefit within the OpenJDK itself 
since it's a maintenance burden.

I'm hoping the fact that the methods are a single line (sans 
comments, descriptors and curly braces) will minimise this burden.

>
> Can you determine if the calls to UNSAFE.freeMemory/allocateMemory come 
from a DBB by looking at the call stack frame above the unsafe call?
>
> Thanks,
> Paul.

Yes that is possible, though I would advise against this because:

 A) Checking the call stack is expensive, and doing this every time we 
    allocate native memory is an easy way to slow down a program,
    or rack up mips.
and 
 B) deciding which code path we're using based on the stack 
    means the DBB class+method (and anything the parsing code 
    mistakes for that class+method) can only ever allocate native 
    memory for DBBs.

What do you think?

Best Regards

Adam Farley

>
>> On Feb 14, 2018, at 3:32 AM, Adam Farley8 <adam.farley at uk.ibm.com> 
wrote:
>> 
>> Hi All,
>> 
>> Currently, diagnostic core files generated from OpenJDK seem to lump 
all 
>> of the 
>> native memory usages together, making it near-impossible for someone to 

>> figure 
>> out *what* is using all that memory in the event of a memory leak.
>> 
>> The OpenJ9 VM has a feature which allows it to track the allocation of 
>> native
>> memory for Direct Byte Buffers (DBBs), and to supply that information 
into 
>> the
>> cores when they are generated. This makes it a *lot* easier to find out 

>> what is using
>> all that native memory, making memory leak resolution less like some 
dark 
>> art, and
>> more like logical debugging.
>> 
>> To use this feature, there is a native method referenced in 
Unsafe.java. 
>> To open
>> up this feature so that any VM can make use of it, the java code below 
>> sets the 
>> stage for it. This change starts letting people call DBB-specific 
methods 
>> when 
>> allocating native memory, and getting into the habit of using it.
>> 
>> Thoughts?
>> 
>> Best Regards
>> 
>> Adam Farley
>> 
>> P.S. Code:
>> 
>> diff --git 
>> a/src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template 
>> b/src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template
>> --- 
a/src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template
>> +++ 
b/src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template
>> @@ -85,7 +85,7 @@
>>                 // Paranoia
>>                 return;
>>             }
>> -            UNSAFE.freeMemory(address);
>> +            UNSAFE.freeDBBMemory(address);
>>             address = 0;
>>             Bits.unreserveMemory(size, capacity);
>>         }
>> @@ -118,7 +118,7 @@
>> 
>>         long base = 0;
>>         try {
>> -            base = UNSAFE.allocateMemory(size);
>> +            base = UNSAFE.allocateDBBMemory(size);
>>         } catch (OutOfMemoryError x) {
>>             Bits.unreserveMemory(size, cap);
>>             throw x;
>> diff --git a/src/java.base/share/classes/jdk/internal/misc/Unsafe.java 
>> b/src/java.base/share/classes/jdk/internal/misc/Unsafe.java
>> --- a/src/java.base/share/classes/jdk/internal/misc/Unsafe.java
>> +++ b/src/java.base/share/classes/jdk/internal/misc/Unsafe.java
>> @@ -632,6 +632,26 @@
>>     }
>> 
>>     /**
>> +     * Allocates a new block of native memory for DirectByteBuffers, 
of 
>> the
>> +     * given size in bytes.  The contents of the memory are 
>> uninitialized;
>> +     * they will generally be garbage.  The resulting native pointer 
will
>> +     * never be zero, and will be aligned for all value types. Dispose 

>> of
>> +     * this memory by calling {@link #freeDBBMemory} or resize it with
>> +     * {@link #reallocateDBBMemory}.
>> +     *
>> +     * @throws RuntimeException if the size is negative or too large 
>> +     *                          for the native size_t type
>> +     *
>> +     * @throws OutOfMemoryError if the allocation is refused by the 
>> system
>> +     *
>> +     * @see #getByte(long)
>> +     * @see #putByte(long, byte)
>> +     */
>> +    public long allocateDBBMemory(long bytes) {
>> +        return allocateMemory(bytes);
>> +    }
>> + 
>> +    /**
>>      * Resizes a new block of native memory, to the given size in 
bytes. 
>> The
>>      * contents of the new block past the size of the old block are
>>      * uninitialized; they will generally be garbage.  The resulting 
>> native
>> @@ -687,6 +707,27 @@
>>     }
>> 
>>     /**
>> +     * Resizes a new block of native memory for DirectByteBuffers, to 
the
>> +     * given size in bytes.  The contents of the new block past the 
size 
>> of
>> +     * the old block are uninitialized; they will generally be 
garbage. 
>> The
>> +     * resulting native pointer will be zero if and only if the 
requested 
>> size
>> +     * is zero.  The resulting native pointer will be aligned for all 
>> value
>> +     * types.  Dispose of this memory by calling {@link 
#freeDBBMemory}, 
>> or
>> +     * resize it with {@link #reallocateDBBMemory}.  The address 
passed 
>> to
>> +     * this method may be null, in which case an allocation will be 
>> performed.
>> +     *
>> +     * @throws RuntimeException if the size is negative or too large 
>> +     *                          for the native size_t type
>> +     *
>> +     * @throws OutOfMemoryError if the allocation is refused by the 
>> system
>> +     *
>> +     * @see #allocateDBBMemory
>> +     */
>> +    public long reallocateDBBMemory(long address, long bytes) {
>> +        return reallocateMemory(address, bytes);
>> +    }
>> +
>> +    /**
>>      * Sets all bytes in a given block of memory to a fixed value
>>      * (usually zero).
>>      *
>> @@ -918,6 +959,17 @@
>>         checkPointer(null, address);
>>     }
>> 
>> +    /**
>> +     * Disposes of a block of native memory, as obtained from {@link
>> +     * #allocateDBBMemory} or {@link #reallocateDBBMemory}.  The 
address 
>> passed
>> +     * to this method may be null, in which case no action is taken.
>> +     *
>> +     * @see #allocateDBBMemory
>> +     */
>> +    public void freeDBBMemory(long address) {
>> +        freeMemory(address);
>> +    }
>> +
>>     /// random queries
>> 
>>     /**
>> 
>> Unless stated otherwise above:
>> IBM United Kingdom Limited - Registered in England and Wales with 
number 
>> 741598. 
>> Registered office: PO Box 41, North Harbour, Portsmouth, Hampshire PO6 
3AU
>


Unless stated otherwise above:
IBM United Kingdom Limited - Registered in England and Wales with number 
741598. 
Registered office: PO Box 41, North Harbour, Portsmouth, Hampshire PO6 3AU


More information about the core-libs-dev mailing list