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