The interviewer asks how many bytes the new Object occupies in the memory, you have to answer this...

The interviewer asks how many bytes the new Object occupies in the memory, you have to answer this...

Staying up late is not easy, and do it and cherish it. Welcome to the veterans of one-key three-connection, for encouragement, thank you very much.


How to know the size of an object in memory? There is something called sizeOf in C language, it is very convenient to know the size of the object. But Java doesn't have such a thing, don't panic, Java itself has an Agent technology.

Java Agent technology

What mechanism is Agent?

For the jvm virtual machine, to load a class to the memory, an agent can be added during the process of loading the memory. This agent can intercept these class files (binary codes such as 001, 010), and can modify them at will, of course, Read the size of the entire Object.

You can refer to this article to learn more about the principle and practice of Java dynamic debugging technology

Make an agent that detects the size of the object

Create a new project ObjectSizeAgent and make it into a jar package.

  1. Write an agent class, the format is generally relatively fixed
public class ObjectSizeAgent {

    //Java Instrumentation
    //jvm Instrumentation
    private static Instrumentation inst;

    /**
     *  premain 
     *  
     *  Instrumentation Instrumentation
     *  Instrumentation
     * @param agentArgs
     * @param _inst
     */
    public static void premain (String agentArgs, Instrumentation _inst) {
        inst = _inst;
    }

    /**
     *  premain Instrumentation getObjectSize 
     * @param o
     * @return
     */
    public static long sizeOf (Object o) {
        return inst.getObjectSize(o);
    }
}
 
  1. Make jar package

Different IDE tools have different ways of playing jar.

The process of typing jar in IDEA 2020.2 is as follows:

File->Project Structure

Choose Artifacts

Enter the jar name, create ManiFest, and store it in the src directory

After the creation is complete, the directory is as follows:

The contents of the file MANIFEST.MF:

Manifest-Version: 1.0
Premain-Class: pers.xblzer.tryout.agent.ObjectSizeAgent
 

Finally, mark it into a jar package:

Use Agent to detect object size

Import the produced jar package in the experimental project, either maven or ordinary jar package can be imported.

PS: Let me write about the process of making local maven jar packages.

  1. Copy the produced jar package to a place, D:\works\3rd_jar, nothing else, just for convenience
  2. Bale
mvn install:install-file -DgroupId=pers.xblzer.tryout -DartifactId=ObjectSizeAgent -Dversion=1.0 -Dpackaging=jar -Dfile=D:\works\3rd_jar\ObjectSizeAgent.jar -DgeneratePom=true -DcreateChecksum=true -Dmaven.wagon.http.ssl.insecure=true -Dmaven.wagon.http.ssl.allowall=true
 
  1. Other project references:
<dependency>
    <groupId>pers.xblzer.tryout</groupId>
    <artifactId>ObjectSizeAgent</artifactId>
    <version>1.0</version>
</dependency>
 

Experiment code:

public class TestObjectSize {

    public static void main(String[] args) {
//      //  XX:+UseCompressedClassPointer XX:+UseCompressedOops
        //16  = markword 8 + classpointer 4 + padding 4
        System.out.println("new Object size:" + ObjectSizeAgent.sizeOf(new Object()));
        //16  = markword 8 + classpointer 4 +   4 + padding 0 8 
        System.out.println("new array size:" + ObjectSizeAgent.sizeOf(new int[]{}));
        //32  8 
        System.out.println("new a common class size:" + ObjectSizeAgent.sizeOf(new P()));

        //  XX:-UseCompressedClassPointer XX:+UseCompressedOops
        //16  = markword 8 + classpointer 8 + padding 0
//       System.out.println("new Object size:" + ObjectSizeAgent.sizeOf(new Object()));
//      //24  = markword 8 + classpointer 8 +   4 + padding 4 8 
//       System.out.println("new array size:" + ObjectSizeAgent.sizeOf(new int[]{}));
//      //40  8 
//       System.out.println("new a common class size:" + ObjectSizeAgent.sizeOf(new P()));
    }

    private static class P {
        //markword 8
        //ClassPinter 4 (-UseCompressedClassPointer   8 +UseCompressedClassPointer   4)

        //4
        int id;
        //Oops 4
        String name;//  +UseCompressedOops   8  -UseCompressedOops   4
        //1
        byte b1;
        //1
        byte b2;
        //Oops 4
        Object o;
        //8
        long i;
    }
}
 

Add the agent we made at runtime: add operating parameters at runtime

-javaagent:D:\works\3rd_jar\ObjectSizeAgent.jar
 

Run it first to see the results, the running environment jdk 1.8, the jvm parameter is the default:

From the running results

new Object()Occupies 16 bytes;

new int[]{}Occupies 16 bytes;

new P()The self-defined class containing various data type attributes occupies 40 bytes.

The result is out, let's analyze why they occupy so many bytes.

The layout of the object in memory

As for the memory layout of objects, there are two types, one is ordinary objects and the other is array objects .

Bytes occupancy and allocation of each part of common object memory:

  1. The object head, called in Hotspot markword, its length is8byte
  2. ClassPointerPointer (such as Object.class)
  • -XX:+UseCompressedClassPointers is the 4bytedefault
  • -XX:-UseCompressedClassPointers is8byte
  1. Instance data

Which byte occupancy situation:

  • -XX:+UseCompressedOops 4byte, default
  • -XX:-UseCompressedOops 8byte

Byte occupancy:

Types of storage Ranges
int 4byte -2^31 ~ 2^31-1
short 2byte -2^15 ~ 2^15-1
long 8byte (-2)^63 ~ 2^63-1
byte 1byte -128 ~ 127
float 4byte
double 8byte
boolean 1byte
char 2byte

The JVM implemented by Hotspot enables memory compression rules (64-bit machines):

  • Below 4G, directly cut the high 32 bits
  • 4G~32G, memory compression is enabled by default
  • Above 32G, compression is invalid, use 64-bit

Therefore, the larger the memory, the better.

  1. PaddingAlign

This alignment is a multiple of 8. For 64-bit machines, it reads in blocks, not bytes. Each block stores bytes that are multiples of 8, so it has an alignment mechanism.

The allocation of bytes in each part of the array object memory:

  1. Object header markword8 bytes
  2. ClassPointerPointer, same as ordinary object, compressed 4 bytes, uncompressed 8 bytes
  3. Array length 4 bytes
  4. Array data
  5. Align multiples of 8

Calculate the number of bytes occupied by new Object()

Based on the above analysis, let's verify the calculation results of the program written earlier:

fornew Object()

  • 1. markwordaccount for8
  • ClassPointer: My machine's memory is 8G, and the JVM has enabled memory compression rules by default, so ClassPointer will take up here4
  • Example data: I just created a new Object(), without any reference type and expense type, this part does not occupy bytes
  • PaddingAlignment: the front 8+4+0=12 bytes, because it needs to meet the multiple of 8, so it needs to16

Therefore, it new Object()occupies 16 bytes.

fornew int[]{}

  • markword: 8 bytes
  • ClassPointer: 4 bytes
  • : 4 bytes
  • : 0 bytes
  • PaddingAlignment: The front 8+4+4+0=16, which is already a multiple of 8, there is no need to align here

Therefore, new int[]{}16 bytes are occupied.

For my own definitionnew P()

private static class P {
   //markword 8
   //ClassPinter 4 (-UseCompressedClassPointer   8 +UseCompressedClassPointer   4)

   //4
    int id;
   //Oops 4
    String name;//  +UseCompressedOops   8  -UseCompressedOops   4
   //1
    byte b1;
   //1
    byte b2;
   //Oops 4
    Object o;
   //8
    long i;
}
 
  • markword 8 bytes
  • ClassPointer 4 bytes
  • :
    • int 4 bytes
    • String reference type 4 bytes
    • Two bytes 1*2=2 bytes
    • Object o reference type 4 bytes
    • long 8 bytes
  • PaddingAlignment: first calculate whether it is a multiple of 8 8+4+4+4+2+4+8=34, it needs to be filled to a multiple of 8, and to 40

Therefore, new P()40 bytes are occupied in this example .

You can debug this program according to the jvm parameters, and you will get different results. Mainly the following two parameters:

-XX:(+/-)UseCompressedClassPointers
-XX:(+/-))UseCompressedOops
 

Over. the above.


No public starting line Barry ER , welcome old iron were concerned about reading correction. Code repository GitHub github.com/xblzer/Java...