文章目录
- 1 JOL
- 2 对象大小计算
- 2.1 只开启普通指针压缩
- 2.2 开启普通指针压缩和开启类指针压缩
- 2.3 不开启压缩
- 2.4 计算总结
- 2.5 加餐
1 JOL
JOL(Java Object Layout),是openjdk的一个工具,可以查看详细的对象布局。
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.16</version>
</dependency>
把包引入到项目中,放一段测试用的代码
import org.openjdk.jol.info.ClassLayout;
import java.util.List;
/**
* @author 编程还未
*/
public class TestJOL {
public static void main(String[] args) {
User user = new User();
System.out.println(ClassLayout.parseInstance(user).toPrintable());
}
static class User {
byte a;
short b;
int c;
long d;
float e;
double f;
boolean g;
char h;
String i;
Child child;
List<Child> childList;
}
static class Child {
String name;
}
}
开启指针压缩(-XX:+UseCompressedOops
)运行结果如下:
com.program_highway.TestJOL$User object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
8 4 (object header: class) 0x00c01200
12 4 int User.c 0
16 8 long User.d 0
24 8 double User.f 0.0
32 4 float User.e 0.0
36 2 short User.b 0
38 2 char User.h
40 1 byte User.a 0
41 1 boolean User.g false
42 2 (alignment/padding gap)
44 4 java.lang.String User.i null
48 4 com.program_highway.TestJOL.Child User.child null
52 4 java.util.List User.childList null
Instance size: 56 bytes
Space losses: 2 bytes internal + 0 bytes external = 2 bytes total
关闭指针压缩(-XX:-UseCompressedOops
)运行结果如下:
com.program_highway.TestJOL$User object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
8 4 (object header: class) 0x00c01200
12 4 int User.c 0
16 8 long User.d 0
24 8 double User.f 0.0
32 4 float User.e 0.0
36 2 short User.b 0
38 2 char User.h
40 1 byte User.a 0
41 1 boolean User.g false
42 6 (alignment/padding gap)
48 8 java.lang.String User.i null
56 8 com.program_highway.TestJOL.Child User.child null
64 8 java.util.List User.childList null
Instance size: 72 bytes
Space losses: 6 bytes internal + 0 bytes external = 6 bytes total
2 对象大小计算
对象大小=对象头+实例数据
本小节内的运行结果,还是用JOL中的Java示例,Java1.8版本
alignment/padding gap
:对齐/填充间隙(基本数据类型用的)。单个对象内部的成员变量填充对齐。开启指针压缩按4的倍数补齐;关闭指针压缩按8的倍数补齐。因为对象内部的引用类型要么4bytes要么8bytes,所以说这个属性是基本数据类型对齐用的,下面不再重复解释。
object alignment gap
:对象对齐间隙。单个对象内部整体按8的倍数对齐。
-XX:+UseCompressedOops
:普通指针压缩。64位HotSpot VM1.6 update14 开始正式支持。会把对象内的普通对象实例由8 bytes(64位)压缩到4 bytes(32位)。
-XX:+UseCompressedClassPointers
:HotSpot会把对象头中_metadata
指向klass的指针压缩为一个无符号32位整数,4bytes。
2.1 只开启普通指针压缩
JVM参数:-XX:+UseCompressedOops -XX:-UseCompressedClassPointers
com.program_highway.jol.TestJOL$User object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
8 8 (object header: class) 0x00000266a13836e8
16 8 long User.d 0
24 8 double User.f 0.0
32 4 int User.c 0
36 4 float User.e 0.0
40 2 short User.b 0
42 2 char User.h
44 1 byte User.a 0
45 1 boolean User.g false
46 2 (alignment/padding gap)
48 4 java.lang.String User.i null
52 4 com.program_highway.jol.TestJOL.Child User.child null
56 4 java.util.List User.childList null
60 4 (object alignment gap)
Instance size: 64 bytes
Space losses: 2 bytes internal + 4 bytes external = 6 bytes total
该情况下计算:
对象大小=对象头+实例数据
对象大小=64 bytes
对象头=16 bytes,包含:object header: mark 8 bytes 和 object header: class 8 bytes
实例数据=分两大部分,一部分是基本数据类型,一部分是引用类型(对象)。基本数据类型的大小=8+8+4+4+2+2+1+1=30 bytes,补齐补2个bytes,32 bytes;引用类型的大小=4+4+4=12 bytes;
最终结果:对象大小(64 byets)=对象头(16bytes)+实例数据【基础类型(32bytes)+引用类型(12bytes)】+ 对象对齐间隙(4 bytes)
2.2 开启普通指针压缩和开启类指针压缩
JVM参数:-XX:+UseCompressedOops -XX:+UseCompressedClassPointers
注意:-XX:+UseCompressedClassPointers
参数依赖-XX:+UseCompressedOops
这是JVM1.8默认的配置,两个压缩都开启。
com.program_highway.jol.TestJOL$User object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
8 4 (object header: class) 0xf800c143
12 4 int User.c 0
16 8 long User.d 0
24 8 double User.f 0.0
32 4 float User.e 0.0
36 2 short User.b 0
38 2 char User.h
40 1 byte User.a 0
41 1 boolean User.g false
42 2 (alignment/padding gap)
44 4 java.lang.String User.i null
48 4 com.program_highway.jol.TestJOL.Child User.child null
52 4 java.util.List User.childList null
Instance size: 56 bytes
Space losses: 2 bytes internal + 0 bytes external = 2 bytes total
该情况下计算
对象大小=对象头+实例数据
对象大小=56 bytes
对象头=12 bytes,包含:object header: mark 8 bytes 和 object header: class 4 bytes
实例数据=分两大部分,一部分是基本数据类型,一部分是引用类型(对象)。基本数据类型的大小=8+8+4+4+2+2+1+1=30 bytes,补齐补2个bytes,32 bytes;引用类型的大小=4+4+4=12 bytes;
最终结果:对象大小(64 bytes)=对象头(12 bytes)+实例数据【基础类型(32 bytes)+引用类型(12 bytes)】
能被8整除,就不需要补齐了。
2.3 不开启压缩
JVM参数:-XX:-UseCompressedOops -XX:-UseCompressedClassPointers
com.program_highway.jol.TestJOL$User object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
8 8 (object header: class) 0x000001c320aa36e8
16 8 long User.d 0
24 8 double User.f 0.0
32 4 int User.c 0
36 4 float User.e 0.0
40 2 short User.b 0
42 2 char User.h
44 1 byte User.a 0
45 1 boolean User.g false
46 2 (alignment/padding gap)
48 8 java.lang.String User.i null
56 8 com.program_highway.jol.TestJOL.Child User.child null
64 8 java.util.List User.childList null
Instance size: 72 bytes
Space losses: 2 bytes internal + 0 bytes external = 2 bytes total
该情况下计算
对象大小=对象头+实例数据
对象大小=72 bytes
对象头=16 bytes,包含:object header: mark 8 bytes 和 object header: class 4 bytes
实例数据=分两大部分,一部分是基本数据类型,一部分是引用类型(对象)。基本数据类型的大小=8+8+4+4+2+2+1+1=30 bytes,8位补齐补2个bytes,32 bytes;引用类型的大小=8+8+8=24 bytes;
最终结果:对象大小(72 byets)=对象头(16 bytes)+实例数据【基础类型(32 bytes)+引用类型(24 bytes)】
能被8整除,就不需要补齐了。
2.4 计算总结
对象大小受三个JVM属性的影响,上述两个-XX:+/-UseCompressedOops -XX:+/-UseCompressedClassPointers
,还有-XX:+/-CompactFields
。
-XX:+/-UseCompressedOops
:开启/关闭普通指针压缩
-XX:+/-UseCompressedClassPointers
:开启/关闭类指针压缩
-XX:+/-CompactFields
:开启/关闭紧凑属性,
这三个属性默认都是开启的,在默认情况下计算对象大小。
对象大小=对象头+实例数据+object alignment gap
(对象对齐间隙)
对象头=12 bytes
实例数据=基础数据类型占用之和+alignment/padding gap
(对齐/填充缝隙)+引用类型占用之和(一个对象占4 bytes)+object alignment gap
(对象对齐间隙)
2.5 加餐
有继承关系如何处理?(默认三个属性都开启)
如果上述类User
有继承关系且父类有属性,User
类会有父类的属性,父类的基本数据类型会单独计算。
Father
类,User
类继承Father
类
static class Father {
private String address;
short age;
}
结果:
com.program_highway.jol.TestJOL$User object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
8 4 (object header: class) 0xf800c182
12 2 short Father.age 0
14 2 (alignment/padding gap)
16 4 java.lang.String Father.address null
20 4 int User.c 0
24 8 long User.d 0
32 8 double User.f 0.0
40 4 float User.e 0.0
44 2 short User.b 0
46 2 char User.h
48 1 byte User.a 0
49 1 boolean User.g false
50 2 (alignment/padding gap)
52 4 java.lang.String User.i null
56 4 com.program_highway.jol.TestJOL.Child User.child null
60 4 java.util.List User.childList null
Instance size: 64 bytes
Space losses: 4 bytes internal + 0 bytes external = 4 bytes total
有继承关系的对象大小=对象头+父基本数据类型占用大小+父基本数据类型的alignment/padding gap
(对齐/填充缝隙)+ 自己的基本数据类型占用大小+自己的基本数据类型的alignment/padding gap
(对齐/填充缝隙)+ 父类和自己的引用类型占用之和(一个对象占4 bytes)