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

Peter Levart peter.levart at gmail.com
Fri Feb 23 15:28:34 UTC 2018


Hi Adam,

Did you know that native memory is already tracked on the Java side for
direct ByteBuffers? See class java.nio.Bits. Could you make use of it?

Regards, Peter

On 23 Feb 2018 1:09 pm, "Adam Farley8" <adam.farley at uk.ibm.com> wrote:

> 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