HotSpot JVM 使用名为 oops (Ordinary Object Pointers) 的数据结构来表示对象,对象在内存中分3部分:
JVM 为了节省内存,如果 heap size 小于 32GB,JVM会自动开启指针压缩。大于32GB会关闭指针压缩。可以用 -XX:-UseCompressedOops tuning flag 强行开启指针压缩。
类型 | 占用空间(byte) |
---|---|
boolean | 1 |
byte | 1 |
short | 2 |
char | 2 |
int | 4 |
float | 4 |
long | 8 |
double | 8 |
object references | 4,如果未开启指针压缩则为 8 |
以下分析基于 jdk11,64位操作系统处理。
其实有3个不同的指标来分析对象大小。
接下来会用代码实际分析对象大小
代码依赖:
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.10</version>
</dependency>
基础代码类:
public class Course {
private String name;
public Course(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
计算公式:对象头 + 实例数据 + 对齐填充字节
代码:
public class ObjectsSizeMain {
public static void main(String[] args) {
String ds = "Data Structures";
Course course = new Course(ds);
System.out.println("The shallow size is: " + VM.current().sizeOf(course));
System.out.println(ClassLayout.parseInstance(course).toPrintable());
}
}
实际输出:
The shallow size is: 16
org.example.objects_size.Course 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) 48 72 06 00 (01001000 01110010 00000110 00000000) (422472)
12 4 java.lang.String Course.name (object)
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
实例数据:Course 类只有一个 String 类的类属性 name ,所以占用 4 字节。
对象头:Couse 类非数组对象,所以占用 12 字节
对齐填充字节: 由于对象头+实例数据=16字节,所以不需要填充,填充字节为 0。
所以 Course 类实例 shallow size 是16字节。
计算公式:对象自身的 Shallow Size + 引用对象的 Shallow Size
代码:
public class ObjectsSizeMain {
public static void main(String[] args) {
String ds = "Data Structures";
Course course = new Course(ds);
System.out.println("course size is: " + VM.current().sizeOf(course));
System.out.println("name size is: " + VM.current().sizeOf(ds));
System.out.println(ClassLayout.parseInstance(ds).toPrintable());
}
}
Course 自身的 shallow size: 16 字节
引用对象的 shallow size:Course 的引用对象为 name, 是个 String 类,可以用ClassLayout.parseInstance(course.getName()).toPrintable()
分析大小。
Course.name 的对象大小:
java.lang.String 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) 08 18 00 00 (00001000 00011000 00000000 00000000) (6152)
12 4 byte[] String.value [68, 97, 116, 97, 32, 83, 116, 114, 117, 99, 116, 117, 114, 101, 115]
16 4 int String.hash 0
20 1 byte String.coder 0
21 3 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 3 bytes external = 3 bytes total
可以看到 String 对象大小为 24 字节。其中请求头 12 字节 ,byte[] 数据 4 字节,hash code 4 字节,byte coder 1 字节,对齐填充 3 字节。
所以 Course 类的 ratained size = 16+24=40 字节。
代码:
public class ObjectsSizeMain {
public static void main(String[] args) {
String ds = "Data Structures";
Course course = new Course(ds);
System.out.println("course size is: " + VM.current().sizeOf(course));
System.out.println("name size is: " + VM.current().sizeOf(ds));
System.out.println(ClassLayout.parseInstance(ds.getBytes()).toPrintable());
}
}
由上已知,Course 类对象大小是 16 字节,String 类对象大小是 24 字节。只要在加上 String 对象实际数据大小就是 Deep Size。
可以通过 ClassLayout.parseInstance(ds.getBytes()).toPrintable()
获取 String 对象实际数据大小。
输出:
[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) 20 08 00 00 (00100000 00001000 00000000 00000000) (2080)
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
String 对象实际数据大小为 32 字节。其中请求头为 16 字节(mark word 8 字节+ kclass 指针 4 字节 + 数据长度 4 字节),实际数据为 15 字节,对齐填充 1 字节。
所以 Course 类的 deep size 为 16+24+32=72 字节。
注:jdk8 下 String 类的 value 为 char[],所以要计算 char[] 的大小,ClassLayout.parseInstance(ds.toCharArray()).toPrintable();
, 由于 char array 为 48 字节,所以jdk8 下 deep size 为 16+24+48=88 字节
原文:https://www.cnblogs.com/stevenvww/p/14978283.html