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

Adam Farley8 adam.farley at uk.ibm.com
Fri Feb 23 12:09:17 UTC 2018


Hi Paul,

The larger picture for (read: effect of) these changes is best explained 
in my email here:

http://mail.openjdk.java.net/pipermail/core-libs-dev/2018-February/051441.html

See the hyperlink I posted, and the few lines before it.

Unfortunately the only understanding I have regarding the workings of the 
native code
is would be derived from the OpenJ9 implimentation. I figured I wouldn't 
be thanked for 
posting that code here, so I posted what code I could share, with the 
additional note 
that the Hotspot native side of this should be implimented by:

1) Turning those Unsafe.java methods into native methods, and make them 
abstract
(descriptor only, for the uninitiated).

2) Find the Hotspot native code for native memory allocation, 
reallocation, and 
freeing. Basically create a method that stores the sum total amount of 
native memory
used by the DBBs, and then calls the regular allocate/reallocate/free 
methods.

E.g.

NM Allocate (Java) - NM Allocate (Native)

DBB NM Allocate (Java) - DBB NM Allocate (Native) - NM allocate (Native)

3) Find the code that prints the current native memory usage in core 
files, and 
add a similar bit to show the native memory usage for DBBs as a subset 
(see the
aforementioned linked link for an example).

This seems like a straightforward task, though that's easy for me to say. 
:)

Does that answer your question?

Also, I'm unfamiliar with Java Flight Recorder. Are other developers on 
the list
familiar with JFR that can snwer this? I'll put the message in IRC as 
well, and
update here if I get any answers.

Best Regards

Adam Farley



From:   Paul Sandoz <paul.sandoz at oracle.com>
To:     Adam Farley8 <adam.farley at uk.ibm.com>
Cc:     core-libs-dev <core-libs-dev at openjdk.java.net>, hotspot-dev 
developers <hotspot-dev at openjdk.java.net>
Date:   22/02/2018 02:20
Subject:        Re: [PATCH] RFR Bug-pending: Enable Hotspot to Track 
Native Memory Usage for Direct Byte Buffers



Hi Adam,

While the burden is minimal there is a principle here that i think we 
should adhere to regarding additions to the code base: additions should 
have value within OpenJDK itself otherwise it can become a thin end of the 
wedge to more stuff (“well you added these things, why not just add these 
too?”).

So i would still be reluctant to add such methods without understanding 
the larger picture and what you have in mind.

Can you send a pointer to your email referring in more detail to the 
larger change sets?

This use-case might also apply in other related areas too with regards to 
logging/monitoring. I would be interested to understand what Java Flight 
Recorder (JFR) does in this regard (it being open sourced soon i believe) 
and how JFR might relate to what you are doing. Should we be adding JFR 
events to unsafe memory allocation? Can JFR efficiently access part of the 
Java call stack to determine the origin?

Thanks,
Paul.

On Feb 19, 2018, at 5:08 AM, Adam Farley8 <adam.farley at uk.ibm.com> wrote:

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




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