On 21/06/2022 12:49 am, Сергей Цыпанов wrote:

Do you get the OOME using Thread.yield() or just a busy-wait?

I reproduce it with busy-wait involving Thread.onSpinWait() and only when the 
test is run with -XX:MaxDirectMemorySize=128m -XX:-ExplicitGCInvokesConcurrent

If I either drop mentioned VM options or use Thread.sleep() OOME will never 
happen (at least on my machine).

That indicates that without those flags, or with the sleep, memory use does not outpace memory return.

P.S. If I use Thread.yield() the problem is not reproduced any more.

Which indicates yielding is having a similar effect to sleeping - though I would expect it to be less pronounced.

P.P.S. How should I interpret this? Thread.onSpinWait() is discouraged for 
busy-waiting?

Thread.onSpinWait _is_ busy-waiting, but it may (depending on architecture) actually execute a more (power) efficient form of busy-wait.

The takeaway from this exercise is that loops with sleeps can't always be replaced by loops that busy-wait. Functionally the logic is the same, but you can't just ignore the concurrency aspects.

Cheers,
David
-----

On 20/06/2022 7:43 pm, Сергей Цыпанов wrote:

Hello,

while playing with Thread.onSpinWait() in busy-wait loops I've replaced 
Thread.sleep() with
preferable (at least as it appears from the JavaDoc) Thread.onSpinWait() in 
java.nio.Bits.

Immediately after that DirectBufferAllocTest started to fail with OOME. This is 
surprising, as the change
does not seem to change any program logic:

Do you get the OOME using Thread.yield() or just a busy-wait? The sleep
limits the computation and ensures other threads can make progress;
whereas a busy loop may not allow that and so you exhaust memory.

David

diff --git a/src/java.base/share/classes/java/nio/Bits.java 
b/src/java.base/share/classes/java/nio/Bits.java
--- a/src/java.base/share/classes/java/nio/Bits.java (revision 
7d4df6a83f6333e0e73686b807ee5d4b0ac10cd2)
+++ b/src/java.base/share/classes/java/nio/Bits.java (date 1655709575452)
@@ -162,8 +162,7 @@
}
try {
if (!jlra.waitForReferenceProcessing()) {
- Thread.sleep(sleepTime);
- sleepTime <<= 1;
+ Thread.onSpinWait();
sleeps++;
}
} catch (InterruptedException e) {

Another surprise here is that when I copy the test as simple Java application
it fails when I run it with the same JVM options (-XX:MaxDirectMemorySize=128m 
-XX:-ExplicitGCInvokesConcurrent),
but doesn't if I put a breakpoint in IntelliJ at sleeps++ and stop there for 
6-7 times while
the test is running. No failure observed if I drop JVM options either.

Is it a bug somewhere in GC/runtime or am I doing something wrong?

Regards,
Sergey Tsypanov

Reply via email to