JVM的栈、堆
栈
什么是栈
- 栈又叫堆栈,是先入后出的数据结构
- 栈是线程私有的,不能互相访问的,栈随着线程的创建而创建,并且在编译时就已确定了栈的大小
- 栈通过栈帧保存了局部变量、对象的内存引用地址、操作栈、动态链接等等
栈帧
栈帧就是栈中的最小单位,第一个方法的调用就会生成栈帧,并将其压如栈中,就是压栈。
第一个方法中又调用了第二个方法,则会生成第二个方法的栈帧,并压栈,当方法执行完或跑出异常时,会进行出栈的操作,并返回值给方法一的栈。
栈溢出的场景
- 递归死循环
递归死循环导致无尽的方法调用,栈帧最终压破了栈的最大值,故而导致了栈溢出
堆
一个对象的大小
一个对象包含了三个主要的内容:对象头、实例数据(成员变量信息)、对齐补充
对象头
(1)普通对象分为两个部分:Mark Word 和 元数据指针(指向对象的class类型)
(2)数组对象分为三个部分:Mark Word、元数据指针和数组长度
Mark Word
(1)GC分代年龄;(2)哈希吗;(3)锁信息(个人理解,线程上锁之后,对象头的锁信息指向线程的栈信息)等
实例数据
(1)基本数据类型(参考基本数据类型大小);(2)引用数据类型(4个字节);
对齐补充
对齐补充是为了保证整个对象大小为8个字节的倍数,当整个对象头
+实例对象
的大小不是8字节倍数时,对齐补充来进行保证。
对象头的大小
Mark Word在不同位数的系统中,大小不同
PS:64位开启指针压缩为-XX:UseCompressedOops
,并且jdk1.8后默认开启
系统 | Mark Word(字节) | 元数据指针 (字节) | 数组长度(字节) | 对象头总计(对象/数组) |
---|---|---|---|---|
32位 | 4 | 4 | 4 | 8/12 |
64位 | 8 | 8 | 4 | 16/20 |
64位开启指针压缩 | 8 | 4 | 4 | 12/16 |
查看对象大小的工具
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.15</version>
</dependency>
(1)对象的内部信息:ClassLayout.parseInstance(obj).toPrintable()
(2)对象的外部信息,包括引用的对象:GraphLayout.parseInstance(obj).toPrintable()
(3)对象占用的总空间:GraphLayout.parseInstance(obj).totalSize()