ThreadMXBean.getThreadAllocatedBytes() allocates memory

Claes Redestad claes.redestad at oracle.com
Sun Sep 18 23:24:05 UTC 2016


Hi Bengt,

I'm not Serviceability, but you know I can't leave them micro-
optimizations alone! :-)

So, reusing cached arrays could be made to work but would require
some synchronization to keep things thread-safe and tidy[1].

This will complicate the code, especially since there's another implied
allocation in getThreadAllocatedBytes. Not to mention that caching
objects which are cheap to allocate is a bit of an performance
anti-pattern.

Adding synchronization also comes with it's own risks, especially as
we're calling into JNI and the VM code takes a somewhat shady mutex
already (Threads_lock).

Generally I don't think there's ever any behavioral guarantees about how
much - or little - a  method won't allocate anything, so calling this a
bug is a bit of a stretch IMO, although it's a bit unfortunate in this
particular case.

TL;DR: I'm a bit skeptic, but if it's important to you to fix this, I
wouldn't think it's impossible.

Thanks!

/Claes

[1] Alternatively we could of course implement a JNI method taking a
long rather than a long[], which would be consistent with other methods
in ThreadImpl.java, but I think we want to avoid going that far.

On 2016-09-18 23:14, Bengt Rutisson wrote:
>
> Hi Serviceability,
>
> Not sure, but I hope this is the correct list to post this on.
>
> I wanted to use the ThreadMXBean.getThreadAllocatedBytes() method to get
> some information about how much memory some Java code allocated.
>
> When I dug into the results they didn't properly add up until I realized
> that the call to getThreadAllocatedBytes() actually allocates memory.
> This was a surprise to me.
>
> I'm attaching a small example to illustrate what I mean.
>
> Running the example renders this output:
>
> $ javac AllocMeasure.java
> $ java AllocMeasure
> Bytes allocated: 48
> Bytes allocated: 48
> Bytes allocated: 48
> Bytes allocated: 48
> Bytes allocated: 48
> Bytes allocated: 48
> Bytes allocated: 48
> Bytes allocated: 48
> Bytes allocated: 48
> Bytes allocated: 48
>
> What I would have expected was that it would say "Bytes allocated: 0"
> since I would like to add my own code between line 9 and 10 in the
> example and get the value for how much memory it allocates. As it is now
> I have to deduct the bytes that the getThreadAllocatedBytes() allocates
> to get the correct result.
>
> The problem is that getThreadAllocatedBytes() is implemented this way:
>
>      public long getThreadAllocatedBytes(long id) {
>          long[] ids = new long[1];
>          ids[0] = id;
>          final long[] sizes = getThreadAllocatedBytes(ids);
>          return sizes[0];
>      }
>
> http://hg.openjdk.java.net/jdk9/jdk9/jdk/file/32d957185656/src/java.management/share/classes/sun/management/ThreadImpl.java#l345
>
> I was surprised to see the "new long[1]". I realize that it is nice to
> reuse getThreadAllocatedBytes(long []) method, but maybe a pre-allocated
> array can be used instead of allocating a new one for each call?
>
> I know the specification for this method is kind of fuzzy, but is this
> to be considered a bug or does it work as intended?
>
> Thanks,
> Bengt


More information about the serviceability-dev mailing list