[PATCH] RFR Bug-pending: Enable Hotspot to Track Native Memory Usage for Direct Byte Buffers (original) (raw)
Zhengyu Gu zgu at redhat.com
Fri Apr 13 14:29:45 UTC 2018
- Previous message: [PATCH] RFR Bug-pending: Enable Hotspot to Track Native Memory Usage for Direct Byte Buffers
- Next message: [PATCH] RFR Bug-pending: Enable Hotspot to Track Native Memory Usage for Direct Byte Buffers
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
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 nmtheadersize 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 sizet 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 sizet 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
- Previous message: [PATCH] RFR Bug-pending: Enable Hotspot to Track Native Memory Usage for Direct Byte Buffers
- Next message: [PATCH] RFR Bug-pending: Enable Hotspot to Track Native Memory Usage for Direct Byte Buffers
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]