-
Bug
-
Resolution: Duplicate
-
P2
-
None
-
25
-
None
Using `UNSAFE.allocateMemory()` and ` UNSAFE.freeMemory()` in certain ways causes the VM to crash.
This issue was only observed on macosx-aarch64 and macosx-x64 and not on Linux and Windows.
Reproduce (see code further below):
make test TEST=open/test/jdk/java/foreign/TestCarrierLocalArenaPoolsStress.java JTREG_REPEAT_COUNT=1000
...
Repeating Jtreg run: 64 out of 1000
...
STARTED TestCarrierLocalArenaPoolsStress::stress 'stress()'
STDOUT:
PT: 0:000007208 EXPANDING VT FJP
PT: 0:005320166 DONE EXPANDING
PT: 0:005854708 CREATING 1024 THREADS USING java.lang.ThreadBuilders$VirtualThreadBuilder@1581572f
PT: 0:011715500 SLEEPING
PT: 10:019071666 INTERRUPTING
PT: 10:020941708 DONE INTERRUPTING
PT: 10:036864250 ALL THREADS COMPLETED
PT: 10:037108583 CREATING 32 THREADS USING java.lang.ThreadBuilders$PlatformThreadBuilder@465bb39d
PT: 10:161722958 SLEEPING
TEST RESULT: Error. Agent communication error: java.io.EOFException; check console log for any additional details
Code:
```
final class TestCarrierLocalArenaPoolsStress {
private static final Unsafe UNSAFE = Unsafe.getUnsafe();
private static final long POOL_SIZE = 64;
private static final VarHandle LONG_HANDLE = JAVA_LONG.varHandle();
/**
* The objective of this test is to try to provoke a situation where threads are
* competing to use allocated pooled memory and then trying to make sure no thread
* can see the same shared memory another thread is using.
*/
@Test
void stress() throws InterruptedException {
final long begin = System.nanoTime();
System.out.println(duration(begin) + "EXPANDING VT FJP");
// Encourage the VT ForkJoin pool to expand/contract so that VT:s will be allocated
// on FJP threads that are later terminated.
LongStream.range(0, Runtime.getRuntime().availableProcessors() * 2L)
.parallel()
// Using a CompletableFuture expands the FJP
.forEach(_ -> Thread.ofVirtual().start(() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException ie) {
throw new RuntimeException(ie);
}
}));
System.out.println(duration(begin) + "DONE EXPANDING");
// Make sure it works for both virtual and platform threads
for (var threadBuilder : List.of(Thread.ofVirtual(), Thread.ofPlatform())) {
final int noThreads = threadBuilder instanceof Thread.Builder.OfVirtual ? 1024 : 32;
System.out.println(duration(begin) + "CREATING " + noThreads + " THREADS USING " + threadBuilder);
final Thread[] threads = IntStream.range(0, noThreads).mapToObj(_ ->
threadBuilder.start(() -> {
final long threadId = Thread.currentThread().threadId();
while (!Thread.interrupted()) {
for (int i = 0; i < 1_000_000; i++) {
// Try to assert no two threads get allocated the same memory region.
final long adr = UNSAFE.allocateMemory(POOL_SIZE);
UNSAFE.putLongVolatile(null, adr, threadId);
long v = UNSAFE.getLongVolatile(null, adr);
assertEquals(threadId, v);
UNSAFE.freeMemory(adr);
//}
}
Thread.yield(); // make sure the driver thread gets a chance.
}
})).toArray(Thread[]::new);
System.out.println(duration(begin) + "SLEEPING");
Thread.sleep(Duration.of(10, SECONDS));
System.out.println(duration(begin) + "INTERRUPTING");
Arrays.stream(threads).forEach(
thread -> {
assertTrue(thread.isAlive());
thread.interrupt();
});
System.out.println(duration(begin) + "DONE INTERRUPTING");
// VTs are daemon threads ...
Arrays.stream(threads).forEach(t -> {
try {
t.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
System.out.println(duration(begin) + "ALL THREADS COMPLETED");
}
System.out.println(duration(begin) + "DONE");
}
}
private static String duration(Long begin) {
var duration = Duration.of(System.nanoTime() - begin, ChronoUnit.NANOS);
long seconds = duration.toSeconds();
int nanos = duration.toNanosPart();
return (Thread.currentThread().isVirtual() ? "VT: " : "PT: ") +
String.format("%3d:%09d ", seconds, nanos);
}
```
This issue was only observed on macosx-aarch64 and macosx-x64 and not on Linux and Windows.
Reproduce (see code further below):
make test TEST=open/test/jdk/java/foreign/TestCarrierLocalArenaPoolsStress.java JTREG_REPEAT_COUNT=1000
...
Repeating Jtreg run: 64 out of 1000
...
STARTED TestCarrierLocalArenaPoolsStress::stress 'stress()'
STDOUT:
PT: 0:000007208 EXPANDING VT FJP
PT: 0:005320166 DONE EXPANDING
PT: 0:005854708 CREATING 1024 THREADS USING java.lang.ThreadBuilders$VirtualThreadBuilder@1581572f
PT: 0:011715500 SLEEPING
PT: 10:019071666 INTERRUPTING
PT: 10:020941708 DONE INTERRUPTING
PT: 10:036864250 ALL THREADS COMPLETED
PT: 10:037108583 CREATING 32 THREADS USING java.lang.ThreadBuilders$PlatformThreadBuilder@465bb39d
PT: 10:161722958 SLEEPING
TEST RESULT: Error. Agent communication error: java.io.EOFException; check console log for any additional details
Code:
```
final class TestCarrierLocalArenaPoolsStress {
private static final Unsafe UNSAFE = Unsafe.getUnsafe();
private static final long POOL_SIZE = 64;
private static final VarHandle LONG_HANDLE = JAVA_LONG.varHandle();
/**
* The objective of this test is to try to provoke a situation where threads are
* competing to use allocated pooled memory and then trying to make sure no thread
* can see the same shared memory another thread is using.
*/
@Test
void stress() throws InterruptedException {
final long begin = System.nanoTime();
System.out.println(duration(begin) + "EXPANDING VT FJP");
// Encourage the VT ForkJoin pool to expand/contract so that VT:s will be allocated
// on FJP threads that are later terminated.
LongStream.range(0, Runtime.getRuntime().availableProcessors() * 2L)
.parallel()
// Using a CompletableFuture expands the FJP
.forEach(_ -> Thread.ofVirtual().start(() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException ie) {
throw new RuntimeException(ie);
}
}));
System.out.println(duration(begin) + "DONE EXPANDING");
// Make sure it works for both virtual and platform threads
for (var threadBuilder : List.of(Thread.ofVirtual(), Thread.ofPlatform())) {
final int noThreads = threadBuilder instanceof Thread.Builder.OfVirtual ? 1024 : 32;
System.out.println(duration(begin) + "CREATING " + noThreads + " THREADS USING " + threadBuilder);
final Thread[] threads = IntStream.range(0, noThreads).mapToObj(_ ->
threadBuilder.start(() -> {
final long threadId = Thread.currentThread().threadId();
while (!Thread.interrupted()) {
for (int i = 0; i < 1_000_000; i++) {
// Try to assert no two threads get allocated the same memory region.
final long adr = UNSAFE.allocateMemory(POOL_SIZE);
UNSAFE.putLongVolatile(null, adr, threadId);
long v = UNSAFE.getLongVolatile(null, adr);
assertEquals(threadId, v);
UNSAFE.freeMemory(adr);
//}
}
Thread.yield(); // make sure the driver thread gets a chance.
}
})).toArray(Thread[]::new);
System.out.println(duration(begin) + "SLEEPING");
Thread.sleep(Duration.of(10, SECONDS));
System.out.println(duration(begin) + "INTERRUPTING");
Arrays.stream(threads).forEach(
thread -> {
assertTrue(thread.isAlive());
thread.interrupt();
});
System.out.println(duration(begin) + "DONE INTERRUPTING");
// VTs are daemon threads ...
Arrays.stream(threads).forEach(t -> {
try {
t.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
System.out.println(duration(begin) + "ALL THREADS COMPLETED");
}
System.out.println(duration(begin) + "DONE");
}
}
private static String duration(Long begin) {
var duration = Duration.of(System.nanoTime() - begin, ChronoUnit.NANOS);
long seconds = duration.toSeconds();
int nanos = duration.toNanosPart();
return (Thread.currentThread().isVirtual() ? "VT: " : "PT: ") +
String.format("%3d:%09d ", seconds, nanos);
}
```
- duplicates
-
JDK-8350455 Malloc errors when concurrently allocating and freeing memory.
-
- Open
-