Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8247615

Initialize the bytes left for the heap sampler

    Details

    • Subcomponent:
    • Resolved In Build:
      b07

      Backports

        Description

        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.

          Attachments

            Issue Links

              Activity

                People

                • Assignee:
                  jcbeyler Jean Christophe Beyler
                  Reporter:
                  jcbeyler Jean Christophe Beyler
                • Votes:
                  0 Vote for this issue
                  Watchers:
                  8 Start watching this issue

                  Dates

                  • Created:
                    Updated:
                    Resolved: