Will ThreadMXBean#getThreadAllocatedBytes return s

2020-07-23 04:43发布

问题:

I want to employ com.sun.management.ThreadMXBean to do something like this:

long before = threadMxBean.getThreadAllocatedBytes(currentThreadId);
seriousBusiness(); // some calls here
long after = threadMxBean.getThreadAllocatedBytes(currentThreadId);
long allocDiff = after - before; // use for stats or whatever

The question is, what does this method actually return: amount of new memory allocated at the moment of method invocation or the size of allocated objects? To be clear on what difference I mean:

1) Say I allocated a huge array in my seriousBusiness() call, so a new memory region was allocated for this purpose and getThreadAllocatedBytes gets incremented by the corresponding value.

2) Some time passed, there was a GC run, that unused array was collected and the memory region is free now.

3) I do some calls again (in the same thread), JVM sees that it doesn't need to allocate new memory and reuses that memory region for the new purpose, which results in getThreadAllocatedBytes value not growing.

I might not be precise on how does JVM memory management work, but the question should be clear as is.

Also, if the first assumption is correct (just new memory allocations count), what would be the right way to do per-thread object allocations / memory footprint measurements?

UPD. I tried to check for myself: http://pastebin.com/ECQpz8g4. (sleeps in the code are to allow me to connect to the JVM with JMC).

TL;DR: Allocate a huge int array, then GC it, then allocate some new objects and check allocated memory. Here's what I got:

So, it appears that GC was actually run and, while memory was certainly allocated and subsequently freed, I got this output:

665328          // before everything started
4295684088      // 4 GiB allocated
4295684296      // did GC (for certain! (really?))
5812441672      // allocated a long string, took new memory

So, I'm just waiting for someone with expertise on JVM memory to tell me if I'm right or where am I wrong.

回答1:

Referencing ThreadMXBean, it reports the number of bytes allocated in heap on behalf of the target thread, but it is implied that this is equivalent to the size of the objects allocated. There is a caveat though:

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

Therefore, I would assume that reclamation of heap space has no effect on the reported values, since it is only reporting the absolute number of bytes allocated, so if you allocate 100 bytes, then 80 bytes are reclaimed, and then you allocate another 100 bytes, the reported (delta) value at the conclusion of these events would be 200 bytes, although the net allocation was only 120.



回答2:

ThreadMXBean.getThreadAllocatedBytes returns the cumulative amount of heap memory allocated by the given thread from the beginning, i.e. this is a monotonically incrementing counter. It is roughly the total size of allocated objects.

EDIT

There is no 'thread ownership' of the allocated heap memory in HotSpot JVM. Once the memory is allocated it is shared among all threads. So, 'per-thread usage' does not really make sense; when JVM allocates an object in heap, it does not know whether this memory has been used before and by whom.