java object多大 java对象内存模型 数组有多长
https://www.cnblogs.com/maxigang/p/9040088.html
https://www.jianshu.com/p/91e398d5d17c
对象结构
在HotSpot虚拟机中,对象在内存中存储的布局可以分为3块区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。下图是普通对象实例与数组对象实例的数据结构:
1 对象头
HotSpot虚拟机的对象头包括两部分信息:
- markword
第一部分markword,用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等,这部分数据的长度在32位和64位的虚拟机(未开启压缩指针)中分别为32bit和64bit,官方称它为“MarkWord”。 - klass
对象头的另外一部分是klass类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例. 32位4字节,64位开启指针压缩或最大堆内存<32g时 4字节,否则8字节 - 数组长度(只有数组对象有) 4字节
如果对象是一个数组, 那在对象头中还必须有一块数据用于记录数组长度.int最大值2g,2^31,java数组(包含字符串)最长2g
2 实例数据
实例数据部分是对象真正存储的有效信息,也是在程序代码中所定义的各种类型的字段内容。无论是从父类继承下来的,还是在子类中定义的,都需要记录起来。
Primitive Type | Memory Required(bytes) |
---|---|
boolean | 1 |
byte | 1 |
short | 2 |
char | 2 |
int | 4 |
float | 4 |
long | 8 |
double | 8 |
此外,引用类型在32位系统上每个占用4B, 在64位系统上每个占用8B,开启(默认)指针压缩占用4B
3 对齐填充
第三部分对齐填充并不是必然存在的,也没有特别的含义,它仅仅起着占位符的作用。由于HotSpot VM的自动内存管理系统要求对象起始地址必须是8字节的整数倍,换句话说,就是对象的大小必须是8字节的整数倍。而对象头部分正好是8字节的倍数(1倍或者2倍),因此,当对象实例数据部分没有对齐时,就需要通过对齐填充来补全。
对象大小计算
要点
1. 在32位系统下,存放Class指针的空间大小是4字节,MarkWord是4字节,对象头为8字节。
2. 在64位系统下,存放Class指针的空间大小是8字节,MarkWord是8字节,对象头为16字节。
3. 64位开启指针压缩或者 JVM 堆的最大值小于 32G的情况下,存放Class指针的空间大小是4字节,MarkWord是8字节,对象头为12字节。
MarkWord
为4字节(64位未开启指针压缩的为8字节);5. 静态属性不算在对象大小内。
JDK 1.8,默认启用指针压缩参数就是开启的。
补充:
HotSpot对象模型
HotSpot中采用了OOP-Klass模型,它是描述Java对象实例的模型,它分为两部分:
- 类被加载到内存时,就被封装成了klass,klass包含类的元数据信息,像类的方法、常量池这些信息都是存在klass里的,你可以认为它是java里面的java.lang.Class对象,记录了类的全部信息;
- OOP(Ordinary Object Pointer)指的是普通对象指针,它包含MarkWord 和元数据指针,MarkWord用来存储当前指针指向的对象运行时的一些状态数据;元数据指针则指向klass,用来告诉你当前指针指向的对象是什么类型,也就是使用哪个类来创建出来的;
那么为何要设计这样一个一分为二的对象模型呢?这是因为HotSopt JVM的设计者不想让每个对象中都含有一个vtable(虚函数表),所以就把对象模型拆成klass和oop,其中oop中不含有任何虚函数,而klass就含有虚函数表,可以进行method dispatch。
实践结果:
public class MarkdownMain {
// 关闭指针压缩-XX:-UseCompressedOops
public static void main(String []f) {
System.out.println(ClassLayout.parseInstance(new Integer(2)).toPrintable());
System.out.println(ClassLayout.parseInstance(new Long(2)).toPrintable());
System.out.println(ClassLayout.parseInstance(new MyLong()).toPrintable());
System.out.println(ClassLayout.parseInstance(new MyLong[]{new MyLong(), new MyLong(), new MyLong()}).toPrintable());
}
private static class MyLong {
public volatile long usefulVal;
public volatile Long anotherVal;
public MyRef myRef;
}
private static class MyRef {
Integer integer = new Integer(15);
}
}
<dependency> <groupId>org.openjdk.jol</groupId> <artifactId>jol-core</artifactId> <version>0.9</version> </dependency>
1)1.8默认:开启指针压缩
java.lang.Integer 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) 67 22 00 f8 (01100111 00100010 00000000 11111000) (-134208921)
12 4 int Integer.value 2
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
java.lang.Long 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) ae 22 00 f8 (10101110 00100010 00000000 11111000) (-134208850)
12 4 (alignment/padding gap)
16 8 long Long.value 2
Instance size: 24 bytes
Space losses: 4 bytes internal + 0 bytes external = 4 bytes total
markdown.MarkdownMain$MyLong 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) 83 f2 00 f8 (10000011 11110010 00000000 11111000) (-134155645)
12 4 java.lang.Long MyLong.anotherVal null
16 8 long MyLong.usefulVal 0
24 4 markdown.MarkdownMain.MyRef MyLong.myRef null
28 4 (loss due to the next object alignment)
Instance size: 32 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
[Lmarkdown.MarkdownMain$MyLong; 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) 02 f3 00 f8 (00000010 11110011 00000000 11111000) (-134155518)
12 4 (object header) 03 00 00 00 (00000011 00000000 00000000 00000000) (3)
16 12 markdown.MarkdownMain$MyLong MarkdownMain$MyLong;.<elements> N/A
28 4 (loss due to the next object alignment)
Instance size: 32 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
整个对象要是8的倍数,否则补全,对象头那一块有些情况也要补全,有两次补全
markdown8字节,class pointer 4字节
引用类型4字节
数组类型的val中,存在【数组长度】个引用类型+数组长度int4
2)关闭指针压缩
-XX:-UseCompressedOops
java.lang.Integer 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) d8 63 ac 10 (11011000 01100011 10101100 00010000) (279733208) 12 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 16 4 int Integer.value 2 20 4 (loss due to the next object alignment) Instance size: 24 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total java.lang.Long 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) 10 9f ac 10 (00010000 10011111 10101100 00010000) (279748368) 12 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 16 8 long Long.value 2 Instance size: 24 bytes Space losses: 0 bytes internal + 0 bytes external = 0 bytes total markdown.MarkdownMain$MyLong 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) 50 53 4f a3 (01010000 01010011 01001111 10100011) (-1555082416) 12 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 16 8 long MyLong.usefulVal 0 24 8 java.lang.Long MyLong.anotherVal null 32 8 markdown.MarkdownMain.MyRef MyLong.myRef null Instance size: 40 bytes Space losses: 0 bytes internal + 0 bytes external = 0 bytes total [Lmarkdown.MarkdownMain$MyLong; 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) 28 5a 4f a3 (00101000 01011010 01001111 10100011) (-1555080664) 12 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1) 16 4 (object header) 03 00 00 00 (00000011 00000000 00000000 00000000) (3) 20 4 (alignment/padding gap) 24 24 markdown.MarkdownMain$MyLong MarkdownMain$MyLong;.<elements> N/A Instance size: 48 bytes Space losses: 4 bytes internal + 0 bytes external = 4 bytes total
markdown8字节,class pointer 8字节
引用类型8字节
https://www.jianshu.com/p/91e398d5d17c 中介绍了另一种看对象模型的方式,还可以看Shallow Size和Retained Size
使用MAT时的Shallow Size和 Retained Size的区别
锁相关:
伪共享相关: