Java thread dynamic memory allocation
Manavjeet Singh
manavjeet18295 at iiitd.ac.in
Mon Sep 28 09:49:06 UTC 2020
Hi!
I was looking around the uses of Thread::_tlab. I found
MemAllocator::allocate() tends to use in most of the cases, by calling
MemAllocator::allocate_inside_tlab.
To understand it's working, I added a boolean field in oopDesc class with
default value false. And while returning from MemAllocator::allocate(), I
alter that boolean field to true.
I also added a native function in System class that would print the value
of the boolean variable in that oopDesc pointer given as an argument.
I observed that only the first allocated object af any class gets the
variable set as true and in others the value of that variable was false.
Can someone help me to comprehend this variation. Also does it mean other
objects are being allocated somewhere else.
Thanks and regards,
Manavjeet Singh
CSD Undergraduate | 2018295
Indraprastha Institute of Information Technology (IIITD)
On Sat, Sep 12, 2020 at 4:00 PM Andrew Haley <aph at redhat.com> wrote:
> 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