Java thread dynamic memory allocation
Andrew Haley
aph at redhat.com
Sat Sep 12 10:30:32 UTC 2020
Hi, and welcome.
On 12/09/2020 09:46, Manavjeet Singh wrote:
> I am currently studying GC and java memory model. From the code, I
> understand that GC provides a TLAB to each thread for unsynchronized
> allocation of the non-humongous objects. But I am not able to
> understand what happens when a "new" operator is called in java
> code. Is the function that tackles this "new" operator defined in
> JavaThread class or some other routine is called.
It's an intrinsic defined in the virtual machine.
> Can you please correct me if I am assuming something wrong, and point me to
> relevant functions so that I can understand better.
OK, here goes.
First you'll need to find thread.hpp in the OpenJDK source code. Look
for this:
ThreadLocalAllocBuffer _tlab; // Thread-local eden
jlong _allocated_bytes; // Cumulative number of bytes allocated on
// the Java heap
If you look around for uses of JavaThread::_tlab you'll see what
happens.
To see how it really works you'll need a disassembly of the code
HotSpot generates. I'm using Intel x86 here because I guess that's
what you have.
Here's my test case:
public class Alloc {
volatile byte[] bytes;
void allocate() {
bytes = new byte[8];
}
public static void main(String[] args) {
long count = Long.parseLong(args[0]);
Alloc a = new Alloc();
for (long i = 0; i < count; i++) {
a.allocate();
}
}
}
Now to disassemble it. You'll need to build hsdis-amd64.so; that's in
jdk/src/utils/hsdis and the instructions for building it are there.
Create a file called .hotspot_compiler containing this:
dontinline Alloc::allocate
print Alloc::allocate
And run java:
java -XX:CompileCommandFile=.hotspot_compiler Alloc 200000000
You'll see the disassembled code for Alloc::allocate
Here's the code that allocates and initializes the object array bytes[],
with my commentary:
The pointer to the current JavaThread is always in r15.
Load _tlab pointer into rbx:
0x00007fae98c2820f: mov rbx,QWORD PTR [r15+0x140]
Add 0x18 (the to total size of the new object):
0x00007fae98c28216: mov r10,rbx
0x00007fae98c28219: add r10,0x18
Make sure we have enough space in our TLAB. If we haven't we'll
have to create a new TLAB; the code to do that is elsewhere.
0x00007fae98c2821d: cmp r10,QWORD PTR [r15+0x150]
0x00007fae98c28224: jae 0x00007fae98c28396
;; B2: # out( B3 ) <- in( B1 ) Freq: 0.9999
OK, so we do have enough space. Let's create our object. First, update
_tlab to point to the end of our new object. After this we've allocated the
space and we have a pointer to it in rbx.
0x00007fae98c2822a: mov QWORD PTR [r15+0x140],r10
The prefetch instructions are just a hint to the processor to load the
next few bytes in the TLAB into the processor cache ready for the next
TLAB allocation:
0x00007fae98c28231: prefetchnta BYTE PTR [r10+0x100]
Initialize the first qword of the object (the lock word):
0x00007fae98c28239: mov QWORD PTR [rbx],0x1
0x00007fae98c28240: prefetchnta BYTE PTR [r10+0x140]
The next two dwords are a pointer to the class and the length of
the array:
0x00007fae98c28248: mov DWORD PTR [rbx+0x8],0x860 ; {metadata({type array byte})}
0x00007fae98c2824f: prefetchnta BYTE PTR [r10+0x180]
Initialize the length field, which is 8:
0x00007fae98c28257: mov DWORD PTR [rbx+0xc],0x8
Now write 8 bytes of zeroes to initialize the object: we just happen
to know that r12 contains 0 at this point.
0x00007fae98c2825e: mov QWORD PTR [rbx+0x10],r12
All clear?
--
Andrew Haley (he/him)
Java Platform Lead Engineer
Red Hat UK Ltd. <https://www.redhat.com>
https://keybase.io/andrewhaley
EAC8 43EB D3EF DB98 CC77 2FAD A5CD 6035 332F A671
More information about the hotspot-gc-dev
mailing list