-
Bug
-
Resolution: Fixed
-
P4
-
11, 15, 16
-
b07
Issue | Fix Version | Assignee | Priority | Status | Resolution | Resolved In Build |
---|---|---|---|---|---|---|
JDK-8254179 | 11.0.10-oracle | Daniil Titov | P4 | Resolved | Fixed | b01 |
JDK-8252503 | 11.0.9 | Jean Christophe Beyler | P4 | Resolved | Fixed | b06 |
Copied over from https://mail.openjdk.java.net/pipermail/serviceability-dev/2020-June/031758.html
JVMTI callback SampledObjectAlloc is currently always called for the first
allocation of a thread. This generates a lot of bias in an application that
regularly starts new threads.
I tested this with latest Java 11 and Java 15.
E.g. here is a sample that creates 100 threads and allocates one object in
each thread.
public class AllocationProfilingBiasReproducer {
public static void main(String[] args) throws Exception {
for (int i = 0; i < 100; i++) {
new Thread(new Task(), "Task " + i).start();
Thread.sleep(1);
}
Thread.sleep(1000);
}
private static class Task implements Runnable {
@Override
public void run() {
new A();
}
}
private static class A {
}
}
I built a simple JVMTI agent that registers SampledObjectAlloc callback and
sets interval to 1 MB with SetHeapSamplingInterval. The callback simply
logs thread name and class name of allocated object.
I see the following output:
SampledObjectAlloc Ljava/lang/String; via Task 0
SampledObjectAlloc LAllocationProfilingBiasReproducer$A; via Task 1
SampledObjectAlloc LAllocationProfilingBiasReproducer$A; via Task 2
SampledObjectAlloc LAllocationProfilingBiasReproducer$A; via Task 3
SampledObjectAlloc LAllocationProfilingBiasReproducer$A; via Task 4
SampledObjectAlloc LAllocationProfilingBiasReproducer$A; via Task 5
SampledObjectAlloc LAllocationProfilingBiasReproducer$A; via Task 6
SampledObjectAlloc LAllocationProfilingBiasReproducer$A; via Task 7
SampledObjectAlloc LAllocationProfilingBiasReproducer$A; via Task 8
SampledObjectAlloc LAllocationProfilingBiasReproducer$A; via Task 9
SampledObjectAlloc LAllocationProfilingBiasReproducer$A; via Task 10
...
This is not expected.
I set a breakpoint in my SampledObjectAlloc callback and observed the
following:
In MemAllocator::Allocation::notify_allocation_jvmti_sampler() the local
var bytes_since_last is always 0xf1f1f1f1f1f1f1f1 for first allocation of a
thread. So first allocation is always reported to my agent.
ThreadLocalAllocBuffer::_bytes_since_last_sample_point does not seem to be
explicitly initialized before accessing it for the first time. I assume
0xf1f1f1f1f1f1f1f1 is a default value provided by some Hotspot allocator.
Only after the first event fired, notify_allocation_jvmti_sampler
calls ThreadLocalAllocBuffer::set_sample_end which initializes
_bytes_since_last_sample_point to a proper value.
JVMTI callback SampledObjectAlloc is currently always called for the first
allocation of a thread. This generates a lot of bias in an application that
regularly starts new threads.
I tested this with latest Java 11 and Java 15.
E.g. here is a sample that creates 100 threads and allocates one object in
each thread.
public class AllocationProfilingBiasReproducer {
public static void main(String[] args) throws Exception {
for (int i = 0; i < 100; i++) {
new Thread(new Task(), "Task " + i).start();
Thread.sleep(1);
}
Thread.sleep(1000);
}
private static class Task implements Runnable {
@Override
public void run() {
new A();
}
}
private static class A {
}
}
I built a simple JVMTI agent that registers SampledObjectAlloc callback and
sets interval to 1 MB with SetHeapSamplingInterval. The callback simply
logs thread name and class name of allocated object.
I see the following output:
SampledObjectAlloc Ljava/lang/String; via Task 0
SampledObjectAlloc LAllocationProfilingBiasReproducer$A; via Task 1
SampledObjectAlloc LAllocationProfilingBiasReproducer$A; via Task 2
SampledObjectAlloc LAllocationProfilingBiasReproducer$A; via Task 3
SampledObjectAlloc LAllocationProfilingBiasReproducer$A; via Task 4
SampledObjectAlloc LAllocationProfilingBiasReproducer$A; via Task 5
SampledObjectAlloc LAllocationProfilingBiasReproducer$A; via Task 6
SampledObjectAlloc LAllocationProfilingBiasReproducer$A; via Task 7
SampledObjectAlloc LAllocationProfilingBiasReproducer$A; via Task 8
SampledObjectAlloc LAllocationProfilingBiasReproducer$A; via Task 9
SampledObjectAlloc LAllocationProfilingBiasReproducer$A; via Task 10
...
This is not expected.
I set a breakpoint in my SampledObjectAlloc callback and observed the
following:
In MemAllocator::Allocation::notify_allocation_jvmti_sampler() the local
var bytes_since_last is always 0xf1f1f1f1f1f1f1f1 for first allocation of a
thread. So first allocation is always reported to my agent.
ThreadLocalAllocBuffer::_bytes_since_last_sample_point does not seem to be
explicitly initialized before accessing it for the first time. I assume
0xf1f1f1f1f1f1f1f1 is a default value provided by some Hotspot allocator.
Only after the first event fired, notify_allocation_jvmti_sampler
calls ThreadLocalAllocBuffer::set_sample_end which initializes
_bytes_since_last_sample_point to a proper value.
- backported by
-
JDK-8252503 Initialize the bytes left for the heap sampler
-
- Resolved
-
-
JDK-8254179 Initialize the bytes left for the heap sampler
-
- Resolved
-