Java目标

前言

本文将教你怎么计算Java目标内存中的巨细

当你 new 一个目标时,假如你对它在内存中,到底什么样,究竟占多大内存感兴趣。本文能够快速的给您答案。
文章中的比如,默许JVM64位,无紧缩。

内存布局

Java内存布局 = 目标头 + 实例数据 +对齐填充

目标内存巨细

一般Java目标 = 目标头(16字节) + 实例数据(各种变量累计巨细) +对齐填充(弥补至8的整数倍)

数组目标 = 目标头(12字节) + 实例数据(各种变量累计巨细) +对齐填充(弥补至8的整数倍)

只看上面对于没触摸过这方面的同学,肯定有难度,这儿仅仅先给我们个形象。别急,等看完下面你就会知道具体的意义了。

图片解说

5分钟,带你理解Java对象的内存布局

1.目标头

目标头由,markword+类型指针+数组长度组成。
一般目标:markword+类型指针 = 8字节 + 4字节 = 12字节
数组目标:markword+类型指针 + 数组长度 = 8字节 + 4字节 +4字节 = 16字节

1.1 markword

在64位JVM中,markword是一个8字节的数据。一字节8位,所以markword是一个64位的数据。

在32位JVM中,成果不同,这儿不做赘述。

markword图解

不同的位数,代表意义不同。这儿引证Mark Word 详解文章中的图片。

5分钟,带你理解Java对象的内存布局

无锁目标的markword

或许没触摸过的同学看不懂该图,我再举个比如。咱们都知道能够经过synchronized锁目标,来做同步操作。

一个目标创立出来没有被锁过,它的markword应该是下图这样的。

5分钟,带你理解Java对象的内存布局
其余锁的状态看法,能够参考上图。
这儿需要留意,hashCode的值,只要在调用hashcode()办法后,才会改动值。

1.2 类型指针

巨细为4字节,指向办法区中,该目标的类型。

1.3 数组长度

只要当创立的是数组时,才有该部分,巨细为4字节,代表当前数组的长度非数组时,不存在

即:一般目标目标头 = markword + 类型指针
数组目标 = markword + 类型指针 +数组长度

2.实例数据

一个目标的实例数据巨细,等于它所有成员变量巨细,以及承继类的变量的巨细的和。

假如你的目标不承继任何目标,只要一个int型变量。那么你的实例数据巨细就为4字节

假如目标A的父类有一个boolean类型变量,目标A有一个char类型变量。
A目标的实例数据巨细 = boolean(1字节)+char(2字节

无论父类的变量是private仍是public润饰,都会算在子类的实例数据中。父类的父类也会算在实例数据中。

留意一点,静态变量存放在办法区,因此不占用目标内存。

3.对齐填充

一个目标巨细必须为8的整数倍。假如目标头+实例数据 = 57个字节。那么对齐填充就为7字节。目标头+实例数据+对齐填充 = 64字节。正好8的整数倍。你能够理解为对齐填充便是凑数用的。

实例解说

下面经过一个具体比如,以及运转成果,来印证下目标内存布局是否如上图所说。
本文含有运转后的成果。我们能够直接经过代码和成果来加深形象,无需实机运转代码。

怎么查看目标

引进一个三方库:jol,经过这个库,能够打印目标内存布局

implementation group: 'org.openjdk.jol', name: 'jol-core', version: '0.17'

辅助类Student

/**
 * Author(作者):jtl
 * Date(日期):2023/3/26 19:20
 * Detail(概况):学生类
 */
public class Student extends Person{
    String name = "ZhangSan";// 目标引证:4字节
    boolean isRealMan;//boolean:1字节
    int age = 10;//boolean:1字节
    char score ='A';//char:2字节
    long time = 20230326;//long:8字节
    Student deskMate;//目标引证:4字节
    public Student() {
    }
    static int grade;
    public boolean isRealMan() {
        return isRealMan;
    }
    public void setRealMan(boolean realMan) {
        isRealMan = realMan;
    }
}

Student的父类Person

该类为了印证,创立Student目标时,Person类的所有变量(包括私有目标),都会占用Student目标实例数据巨细。

/**
 * Author(作者):jtl
 * Date(日期):2023/3/28 16:07
 * Detail(概况):父类,Person类
 */
public class Person extends Object {
    private float time = 0L;
    String country = "China";
}

实践运转代码

这儿举了5种比如,经过下文的运转成果,我们能够进行对比,加深形象。

public class Main {
    public static void main(String[] args) throws InterruptedException {
        Student student = new Student();
        System.out.println("-----------------------------第一阶段 new 目标-------------------------------");
        System.out.println(ClassLayout.parseInstance(student).toPrintable());
        System.out.println("-----------------------------第二阶段 hashcode-------------------------------");
        student.hashCode();
        System.out.println(ClassLayout.parseInstance(student).toPrintable());
        synchronized (student){
            System.out.println("-----------------------------第三阶段 synchronized加锁-------------------------------");
            System.out.println("synchronized (student):\n"+ClassLayout.parseInstance(student).toPrintable());
        }
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (student){
                    System.out.println("-----------------------------第四阶段 synchronized加锁-------------------------------");
                    System.out.println("new Thread:synchronized (student):\n"+ClassLayout.parseInstance(student).toPrintable());
                }
            }
        }).start();
        synchronized (student) {
            System.out.println("-----------------------------第五阶段 Student[] 数组-------------------------------");
            System.out.println(ClassLayout.parseInstance(new Student[]{new Student(), new Student(), new Student()}).toPrintable());
        }
    }
}

内存布局

这儿能够看到的是,只要调用了hashcode办法后。markword中才会修改对应方位的数据。 别的只要目标为数组时,才会有数组长度(array length) 这个选项,巨细为4字节

> Task :Main.main()
-----------------------------第一阶段 new 目标-------------------------------
org.example.Student object internals:
OFF  SZ                  TYPE DESCRIPTION               VALUE
  0   8                       (object header: mark)     0x0000000000000001 (non-biasable; age: 0)
  8   4                       (object header: class)    0x01000be8
 12   4                 float Person.time               0.0
 16   4      java.lang.String Person.country            (object)
 20   4                   int Student.age               10
 24   8                  long Student.time              20230326
 32   2                  char Student.score             A
 34   1               boolean Student.isRealMan         false
 35   1                       (alignment/padding gap)   
 36   4      java.lang.String Student.name              (object)
 40   4   org.example.Student Student.deskMate          null
 44   4                       (object alignment gap)    
Instance size: 48 bytes
Space losses: 1 bytes internal + 4 bytes external = 5 bytes total
-----------------------------第二阶段 hashcode-------------------------------
org.example.Student object internals:
OFF  SZ                  TYPE DESCRIPTION               VALUE
  0   8                       (object header: mark)     0x00000073035e2701 (hash: 0x73035e27; age: 0)
  8   4                       (object header: class)    0x01000be8
 12   4                 float Person.time               0.0
 16   4      java.lang.String Person.country            (object)
 20   4                   int Student.age               10
 24   8                  long Student.time              20230326
 32   2                  char Student.score             A
 34   1               boolean Student.isRealMan         false
 35   1                       (alignment/padding gap)   
 36   4      java.lang.String Student.name              (object)
 40   4   org.example.Student Student.deskMate          null
 44   4                       (object alignment gap)    
Instance size: 48 bytes
Space losses: 1 bytes internal + 4 bytes external = 5 bytes total
-----------------------------第三阶段 synchronized加锁-------------------------------
synchronized (student):
org.example.Student object internals:
OFF  SZ                  TYPE DESCRIPTION               VALUE
  0   8                       (object header: mark)     0x000070000dcafac0 (thin lock: 0x000070000dcafac0)
  8   4                       (object header: class)    0x01000be8
 12   4                 float Person.time               0.0
 16   4      java.lang.String Person.country            (object)
 20   4                   int Student.age               10
 24   8                  long Student.time              20230326
 32   2                  char Student.score             A
 34   1               boolean Student.isRealMan         false
 35   1                       (alignment/padding gap)   
 36   4      java.lang.String Student.name              (object)
 40   4   org.example.Student Student.deskMate          null
 44   4                       (object alignment gap)    
Instance size: 48 bytes
Space losses: 1 bytes internal + 4 bytes external = 5 bytes total
-----------------------------第五阶段 Student[] 数组-------------------------------
[Lorg.example.Student; object internals:
OFF  SZ                  TYPE DESCRIPTION               VALUE
  0   8                       (object header: mark)     0x0000000000000001 (non-biasable; age: 0)
  8   4                       (object header: class)    0x0101ed10
 12   4                       (array length)            3
 16  12   org.example.Student Student;.<elements>       N/A
 28   4                       (object alignment gap)    
Instance size: 32 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
-----------------------------第四阶段 synchronized加锁-------------------------------
new Thread:synchronized (student):
org.example.Student object internals:
OFF  SZ                  TYPE DESCRIPTION               VALUE
  0   8                       (object header: mark)     0x000060000265c002 (fat lock: 0x000060000265c002)
  8   4                       (object header: class)    0x01000be8
 12   4                 float Person.time               0.0
 16   4      java.lang.String Person.country            (object)
 20   4                   int Student.age               10
 24   8                  long Student.time              20230326
 32   2                  char Student.score             A
 34   1               boolean Student.isRealMan         false
 35   1                       (alignment/padding gap)   
 36   4      java.lang.String Student.name              (object)
 40   4   org.example.Student Student.deskMate          null
 44   4                       (object alignment gap)    
Instance size: 48 bytes
Space losses: 1 bytes internal + 4 bytes external = 5 bytes total

上面成果的看法如下图所示:

5分钟,带你理解Java对象的内存布局
别的,对齐填充巨细如下图所示。终究目标巨细,一定是8的整数倍

5分钟,带你理解Java对象的内存布局

至于 (alignment/padding gap) 什么情况下会出现。自己没有细心研讨,感兴趣的同学能够看下jol的源码。下图为源码中的具体方位。

5分钟,带你理解Java对象的内存布局

结尾

至此,Java目标内存布局就讲完了。不知道我们还记住多少呢。假如怕看了不久就忘了,能够收藏本文,点个赞支持下作者。文章中若有过错,能够及时纠正。

本年Java找工作异常困难,希望我们都能够度过这个寒冬。加油!!!

上文的示例代码:Java内存布局 感兴趣的同学,能够下载运转一下。