Finally, I broke all your imagination of Java objects with JOL

brief introduction

The advantage of using object-oriented programming language is that although you don't have a girlfriend, you can still create new objects. Java is an object-oriented programming language. We use java to create new objects every day, but it is estimated that few people know what the new objects look like, whether they are beautiful or ugly, and whether they match our needs?

For ordinary Java programmers, they may never consider the problem of objects in Java. If they don't understand these, they can write code well.

But for a geek who has the spirit of studying, he will certainly think more and more about what the objects in Java are like.

Today, little f introduces you a tool JOL, which can meet all your imagination of Java objects.

More highlights:

Introduction to JOL

The full name of JOL is java object layout. Is a gadget used to analyze the layout of objects in the JVM. Including the occupation of object in memory, the reference of instance object, and so on.

JOL can be used in code or run independently from the command line. I won't introduce the command line in detail here. Today I will mainly explain how to use JOL in code.

To use JOL, you need to add Maven dependencies:

<dependency>
            <groupId>org.openjdk.jol</groupId>
            <artifactId>jol-core</artifactId>
            <version>0.10</version>
</dependency>

After adding dependencies, we can use them.

Analyzing VM information using JOL

First, let's look at how to use JOL to analyze JVM information. The code is very simple:

log.info("{}",VM.current().details());

Output results:

# Running 64-bit HotSpot VM.
# Using compressed oop with 3-bit shift.
# Using compressed klass with 3-bit shift.
# WARNING | Compressed references base/shifts are guessed by the experiment!
# WARNING | Therefore,computed addresses are just guesses,and ARE NOT RELIABLE.
# WARNING | Make sure to attach Serviceability Agent to get the reliable addresses.
# Objects are 8 bytes aligned.
# Field sizes by type: 4,1,2,4,8,8 [bytes]
# Array element sizes: 4,8 [bytes]

In the above output, we can see that objects are 8 bytes aligned, which means that the allocated bytes of all objects are an integer multiple of 8.

Analyzing strings using JOL

None of the above is the focus. The focus is how to use JOL to divide class and instance information.

In fact, the size of objects in Java, except arrays, should be fixed. Let's take a look at the most commonly used string:

log.info("{}",ClassLayout.parseClass(String.class).toPrintable());

In the above example, we use classlayout to parse a string class. First look at the output:

[main] INFO com.flydean.JolUsage - java.lang.String object internals:
 OFFSET  SIZE      TYPE DESCRIPTION                               VALUE
      0    12           (object header)                           N/A
     12     4    byte[] String.value                              N/A
     16     4       int String.hash                               N/A
     20     1      byte String.coder                              N/A
     21     1   boolean String.hashIsZero                         N/A
     22     2           (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 2 bytes external = 2 bytes total

First, explain the meaning of each field. Offset is the offset, that is, the number of bytes occupied to this field position. Size is the size of the following type, type is the type defined in class, description is the description of the type, and value is the value of type in memory.

By analyzing the above output, we can see that there are five parts in the space occupied by the string class. The first part is the object header, accounting for 12 bytes, the second part is the byte array, accounting for 4 bytes, the third part is the hash value represented by int, accounting for 4 bytes, the fourth part is the coder represented by byte, accounting for 1 byte, and the last one is the hashiszero represented by Boolean, accounting for 1 byte, A total of 22 bytes. However, the allocation of object memory in the JVM must be an integer multiple of 8 bytes, so 2 bytes should be completed. The total size of the last string class is 24 bytes.

Someone may want to ask little F. if a lot of data is stored in the string, is the size of the object still 24 bytes?

This question is very well asked. Let's take a look at how to use JOL to parse the information of string objects:

log.info("{}",ClassLayout.parseInstance("www.flydean.com").toPrintable());

In the above example, we used parseinstance instead of parseclass to parse the information of string instances.

Output results:

[main] INFO com.flydean.JolUsage - java.lang.String object internals:
 OFFSET  SIZE      TYPE DESCRIPTION                               VALUE
      0     4           (object header)                           01 c2 63 a2 (00000001 11000010 01100011 10100010) (-1570520575)
      4     4           (object header)                           0c 00 00 00 (00001100 00000000 00000000 00000000) (12)
      8     4           (object header)                           77 1a 06 00 (01110111 00011010 00000110 00000000) (399991)
     12     4    byte[] String.value                              [119,119,46,102,108,121,100,101,97,110,99,111,109]
     16     4       int String.hash                               0
     20     1      byte String.coder                              0
     21     1   boolean String.hashIsZero                         false
     22     2           (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 2 bytes external = 2 bytes total

Let's look at the conclusion first. Like string class, this string object does occupy only 24 bytes.

The result of instance resolution is similar to that of class resolution. Because it is an instance object, there is more value.

We know that after jdk9, the underlying storage of string has changed from char [] to byte [] to save the storage space of string. In the above output, we can see string The value value is really long, but only the reference address of the byte array is saved in the string, so 4 bytes is enough.

Analyzing arrays using JOL

Although the size of string is constant, the size of its underlying array is variable. Let's take another example:

log.info("{}",ClassLayout.parseClass(byte[].class).toPrintable());

Output results:

[main] INFO com.flydean.JolUsage - [B object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0    16        (object header)                           N/A
     16     0   byte [B.<elements>                             N/A
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

Class, you can see that the byte array occupies 16 bytes.

Let's look at the example:

log.info("{}",ClassLayout.parseInstance("www.flydean.com".getBytes()).toPrintable());

Output results:

[main] INFO com.flydean.JolUsage - [B object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           22 13 07 00 (00100010 00010011 00000111 00000000) (463650)
     12     4        (object header)                           0f 00 00 00 (00001111 00000000 00000000 00000000) (15)
     16    15   byte [B.<elements>                             N/A
     31     1        (loss due to the next object alignment)
Instance size: 32 bytes
Space losses: 0 bytes internal + 1 bytes external = 1 bytes total

You can see that the size of the array has really changed, this time to 32 bytes.

Automatic boxing using JOL analysis

As we know, the basic types in java have an object type corresponding to them, such as long and long. Let's analyze the memory differences between them in the JVM:

log.info("{}",ClassLayout.parseClass(Long.class).toPrintable());

Output results:

[main] INFO com.flydean.JolUsage - java.lang.Long object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0    12        (object header)                           N/A
     12     4        (alignment/padding gap)                  
     16     8   long Long.value                                N/A
Instance size: 24 bytes
Space losses: 4 bytes internal + 0 bytes external = 4 bytes total

You can see that a long object takes up 24 bytes, but the value that really stores long only takes up 8 bytes.

Take an example:

log.info("{}",ClassLayout.parseInstance(1234567890111112L).toPrintable());

Output results:

[main] INFO com.flydean.JolUsage - java.lang.Long object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           05 00 00 00 (00000101 00000000 00000000 00000000) (5)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           9a 15 00 00 (10011010 00010101 00000000 00000000) (5530)
     12     4        (alignment/padding gap)                  
     16     8   long Long.value                                1234567890111112
Instance size: 24 bytes
Space losses: 4 bytes internal + 0 bytes external = 4 bytes total

Analyzing reference relationships using JOL

We used JOL to analyze the space usage inside the class. Can we analyze if there are external references?

HashMap hashMap= new HashMap();
hashMap.put("flydean","www.flydean.com");
log.info("{}",GraphLayout.parseInstance(hashMap).toPrintable());

Above, we use a different layout: graphlayout, which can be used to analyze external references.

Output results:

[main] INFO com.flydean.JolUsage - java.util.HashMap@57d5872cd object externals:
          ADDRESS       SIZE TYPE                      PATH                           VALUE
        7875f9028         48 java.util.HashMap                                        (object)
        7875f9058         24 java.lang.String          .table[14].key                 (object)
        7875f9070         24 [B                        .table[14].key.value           [102,110]
        7875f9088         24 java.lang.String          .table[14].value               (object)
        7875f90a0         32 [B                        .table[14].value.value         [119,109]
        7875f90c0         80 [Ljava.util.HashMap$Node; .table                         [null,null,(object),null]
        7875f9110         32 java.util.HashMap$Node    .table[14]                     (object)

From the results, we can see that the HashMap itself occupies 48 bytes, and it references the key and value occupying 24 bytes.

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>