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

Paul Sandoz paul.sandoz at oracle.com
Thu Feb 22 02:18:30 UTC 2018


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



More information about the core-libs-dev mailing list