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

Zhengyu Gu zgu at redhat.com
Fri Apr 13 14:29:45 UTC 2018


Hi Adam,

On 04/13/2018 10:14 AM, Adam Farley8 wrote:
> Hi Alan, Peter,
> 
> I see that native memory is tracked in java.nio.Bits, but that only
> includes what the user thinks they are allocating.
> 
> When the VM adds extra memory to the allocation amount this extra bit is
> not represented in the Bits total.
> A cursory glance shows, minimum, that we round the requested memory
> quantity up to the heap word size in
> the Unsafe.allocateMemory code, and something to do with nmt_header_size
> in os:malloc() (os.cpp) too.

This header overhead only incurs when detail native memory tracking is on.

> 
> Here's a set of solutions for the problem of "what you see isn't what you
> get" for DBBs (3 is my favourite, but I
> suspect 2 is the most likely to be accepted):

I don't understand why you care about this header? The overheads are not 
counted to allocators or memory categories (mtOther in this case), but 
reported by NMT as tracking overhead.

Thanks,

-Zhengyu

> 
> 1) Use the code below to call DBB-specific Unsafe methods, allowing us to
> track the quantity of native
> memory reserved for DBBs at the point of allocation.
> 
> Pros:
> - Doesn't require changing the Bits class.
> - Allows us to easily devise a list of DBB native memory allocation
> locations.
> - Fits with existing OpenJ9 code, which tracks DBB memory usage *after*
> native code has added to the total
> memory requested, resulting in more accurate totals than Bits.
> 
> Cons:
> - Requires some work on the Hotspot side to make it happen if Hotspot
> users want the true benefit.
> OR
> - Requires a commit that only benefits Java if you're running on the
> OpenJ9 VM.
> 
> 2) Modify the Bits code to interrogate the VM via an extra method in
> Unsafe, in order to determine the
> true quantity of native memory that is being allocated.
> 
> E.g. User requests 10 bits, VM says it needs +2, add 12 to cumulative
> total, return "true".
> User later says to free 10 bits, VM says it needs +2, so we subtract 12
> from the total.
> 
> Note: For consistency, the VM and Bits should use the same code when
> figuring out how much space
> will be added to the request by the VM.
> 
> Pros:
> - Much smaller change than (1)
> - Makes Bits much more accurate.
> - Retains the Bits interface, and doesn't require a change to Unsafe.
> 
> Cons:
> - Requires us to add a native method to Bits, or somewhere visible to
> Bits.
> 
> 3) Modify the Bits code to use an internal array for memory reservations,
> returns an index. The user
> can use this index to:
> - Return the amount of memory they requested.
> - Return the amount of memory the VM will actually reserve (Bits will
> retrieve this from the VM via a
> native method).
> - Set the address the VM gave them for this reservation.
> - Free the memory reserved.
> 
> Note: The existing internal totals, along with Shared Secrets, remain.
> 
> Pros:
> - *Much* more accurate memory tracking for DBBs.
> - Easier debugging for DBB overruns, as we know where all the DBBs are.
> - Prevents the user trying to free too much or too little memory for an
> allocated DBB.
> 
> Cons:
> - Many changes to Bits.
> - Native code changes.
> - Probably best to restructure the memory allocation code to share the
> same logic
> (abstracting out the size+x gubbins so Bits' new native code logic remains
> up to date).
> 
> 
> Any thoughts?
> 
> - Adam
> 
> 
> 
> 
>>> 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?
>>>
>> Right, these are the fields that are exposed at runtime via
>> BufferPoolMXBean. A SA based tool could read from a core file. I can't
>> tell if this is enough for Adam, it may be that the his tool reveals
>> more details on the buffers in the pools.
>>
>> -Alan
> 
> 
> 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
> 


More information about the hotspot-dev mailing list