Java目标
前言
本文将教你怎么计算Java目标在内存中的巨细。
当你 new 一个目标时,假如你对它在内存中,到底什么样,究竟占多大内存感兴趣。本文能够快速的给您答案。
文章中的比如,默许JVM为64位,无紧缩。
内存布局
Java内存布局 = 目标头 + 实例数据 +对齐填充
目标内存巨细
一般Java目标 = 目标头(16字节) + 实例数据(各种变量累计巨细) +对齐填充(弥补至8的整数倍)
数组目标 = 目标头(12字节) + 实例数据(各种变量累计巨细) +对齐填充(弥补至8的整数倍)
只看上面对于没触摸过这方面的同学,肯定有难度,这儿仅仅先给我们个形象。别急,等看完下面你就会知道具体的意义了。
图片解说
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 详解文章中的图片。
无锁目标的markword
或许没触摸过的同学看不懂该图,我再举个比如。咱们都知道能够经过synchronized锁目标,来做同步操作。
一个目标创立出来没有被锁过,它的markword应该是下图这样的。
其余锁的状态看法,能够参考上图。
这儿需要留意,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
上面成果的看法如下图所示:
别的,对齐填充巨细如下图所示。终究目标巨细,一定是8的整数倍。
至于 (alignment/padding gap) 什么情况下会出现。自己没有细心研讨,感兴趣的同学能够看下jol的源码。下图为源码中的具体方位。
结尾
至此,Java目标内存布局就讲完了。不知道我们还记住多少呢。假如怕看了不久就忘了,能够收藏本文,点个赞支持下作者。文章中若有过错,能够及时纠正。
本年Java找工作异常困难,希望我们都能够度过这个寒冬。加油!!!
上文的示例代码:Java内存布局 感兴趣的同学,能够下载运转一下。