1

I know the basics of how memory allocation in Java works - that most of the memory the application takes is allocated on the heap, and the heap is shared by all threads, and therefore there is no concept of objects owned by a thread, and you cannot easily calculate how much memory a thread is taking with all the objects it owns.

But I wondered if there is any way to count and sum allocations triggered from a specific thread? The memory allocation is happening on the heap, but it's always triggered by a thread wanting to create an object, so I was wondering if this relationship could be profiled somehow?

My thought is that a typical Spring Boot application will boot, allocate a bunch of objects from the main thread, then start a webserver that spawns threads for handling the HTTP requests and each time a request is received, a thread is assigned to it, and it's handled in that thread. The webserver thread have a specific point where they accept the requests, process them and then send the response. If we could somehow "reset" the allocation stats at the point where the request is accepted and then submit the stats to some collector after the response is sent, we could have very nice statistics about individual endpoints and see how much memory they allocate.

I know this wouldn't be perfect, but with this approach, you'd at least gain some visibility into how much memory is allocated per HTTP request, and you'd be able to see that for example some request is loading half the database into memory and that might be a problem.

Filip Procházka
  • 808
  • 9
  • 31

2 Answers2

2

The following sample code shows how you can determine the amount of (heap) memory allocated during a method call:

import java.lang.management.ManagementFactory;
import com.sun.management.ThreadMXBean;

public class AllocationWatcher {
    public static void main(String[] args) {
        ThreadMXBean threadMxBean = (ThreadMXBean) ManagementFactory.getThreadMXBean();
        threadMxBean.setThreadAllocatedMemoryEnabled(true);

        long startAlloc = threadMxBean.getCurrentThreadAllocatedBytes();
        allocMemory();
        long endAlloc = threadMxBean.getCurrentThreadAllocatedBytes();

        System.out.printf("Thread allocated %,d bytes before the start%n", startAlloc);
        System.out.printf("Thread allocated %,d bytes within allocMemory()%n", endAlloc-startAlloc);
    }
    static void allocMemory() {
        var data = new byte[10_001];
        var data2 = new byte[10_001];
    }
}

The class import com.sun.management.ThreadMXBean is part of the OpenJDK source, so it will probably work with most JVMs (although I cannot give any guarantees).

Thomas Kläger
  • 17,754
  • 3
  • 23
  • 34
1

I think there may be a way to do this with an MXBean, though I cannot give you example code.

There is an interface called com.sun.management.ThreadMXBean in the jdk.management module (javadoc) that has methods that are described like this:

"Returns an approximation of the total amount of memory, in bytes, allocated in heap memory for [a thread]. The returned value is an approximation because some Java virtual machine implementations may use object allocation mechanisms that result in a delay between the time an object is allocated and the time its size is recorded."

My interpretation is that this an accumulator of the sizes of all of a thread's heap allocations.

There are some caveats though. Firstly, the mechanism may not be supported by your JVM. (There are methods to find this out.) Secondly, it needs to be enabled. Thirdly, the fact that it is an approximation may mean that it is not sufficiently accurate for your purposes.

There is section of the Oracle Java Tutorial on how to use MXBeans:

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216