RFR: 8357959: (bf) ByteBuffer.allocateDirect initialization can result in large TTSP spikes [v7]
Aleksey Shipilev
shade at openjdk.org
Tue Jun 3 09:12:54 UTC 2025
On Tue, 3 Jun 2025 08:35:45 GMT, Rohitash Kumar <duke at openjdk.org> wrote:
>> ByteBuffer.allocateDirect uses UNSAFE.setMemory, causing high time-to-safepoint (100+ ms) for large (100 MB+) allocations.
>>
>> This PR applies a simple fix by chunking the zeroing operation within ByteBuffers. A more robust solution would be to add chunking inside UNSAFE.setMemory itself. However Its not that straightforward as mentioned by Aleksey in [JDK-8357959](https://bugs.openjdk.org/browse/JDK-8357959)
>>>Looks like all current uses we care about are in Buffers. Taking a safepoint within cleaning would open some questions whether any VM code expect to see semi-initialized area we are busy cleaning up. For Buffers, this question does not arise. Therefore, we can do the fix in Buffers first, without changing the Unsafe itself.
>>
>> I can pursue that if its preferred. I chose 1 MB as a chunk size some what arbitrarily I am open to suggestion, if there are better options.
>>
>> For verification, I tested the fix against the reproducer - [gist](https://gist.github.com/rk-kmr/be4322b72a14ae04aeefc0260c01acf6) and confirmed that ttsp timing were lower.
>>
>> **before**
>>
>> 0.444s][info][safepoint,stats] ThreadDump [ 13 1 ][ 194156625 65291 194221916 ] 0
>> [0.662s][info][safepoint,stats] ThreadDump [ 13 1 ][ 200013875 87834 200101709 ] 0
>> [0.858s][info][safepoint,stats] ThreadDump [ 13 1 ][ 183762583 43417 183806000 ] 0
>> [1
>>
>> **after**
>>
>> 1.705s][info][safepoint,stats] ThreadDump [ 11 1 ][ 92792 24958 117750 ] 0
>> [1.724s][info][safepoint,stats] ThreadDump [ 11 1 ][ 497375 94041 591416 ] 0
>> [1.736s][info][safepoint,stats] ThreadDump [ 11 1 ][ 156750 47208 203958 ] 0
>> [1.747s][info][safepoint,stats] ThreadDump [ 11 1 ][ 121958 28334 150292 ] 0
>>
>>
>> I added a benchmark to ensure that chunking doesn't introduce significant overhead across different allocation sizes, and following results confirm that.
>>
>> **Before**
>>
>> Benchmark (bytes) Mode Cnt Score Error Units
>> B...
>
> Rohitash Kumar has updated the pull request incrementally with one additional commit since the last revision:
>
> Address PR Comments (rename bench and reduce max alloc size)
Now that clearing code is a bit more complicated, I think we need to extend the test that verifies that DBB is properly initialized. There is already one test, but it is unsatisfactory.
Amend it like this: [8357959-test.txt](https://github.com/user-attachments/files/20565736/8357959-test.txt) -- then run on your new code (`make test TEST=java/nio/Buffer/AllocateDirectInit.java`).
src/java.base/share/classes/java/nio/Bits.java line 248:
> 246: * the starting memory address
> 247: * @param size
> 248: * the number of bytes to set
Bikeshedding: This is probably `count`, not `size`.
src/java.base/share/classes/java/nio/Bits.java line 260:
> 258: offset += len;
> 259: }
> 260: }
So this becomes:
Suggestion:
static void setMemory(long srcAddr, long count, byte value) {
long offset = 0;
while (offset < count) {
long len = Math.min(UNSAFE_SET_THRESHOLD, count - offset);
UNSAFE.setMemory(srcAddr + offset, len, value);
offset += len;
}
}
-------------
PR Review: https://git.openjdk.org/jdk/pull/25487#pullrequestreview-2891346767
PR Review Comment: https://git.openjdk.org/jdk/pull/25487#discussion_r2123164214
PR Review Comment: https://git.openjdk.org/jdk/pull/25487#discussion_r2123168075
More information about the nio-dev
mailing list