JVM对象的创建过程_java创建对象的语句
对象的创建过程
new对象
image-20230226144541919
1:首先判断这个类有没有加载过,没有加载过的先加载到我们JVM内存中。
2:分配内存
- 指针碰撞:默认使用,如果JVM堆中内存绝对规整,使用过的内存放一边,空闲的内存放另一边。中间放着指针分界点,在分配内存的时候将那个指针向空闲空间移动一段对象大小的距离。(垃圾收集器用的是标记整理)
- 空闲列表:JVM堆中内存不规整,已使用和未使用的相互交错,没办法用指针碰撞,JVM必须维护一个列表,记录哪些内存块可用,在分配的时候从列表中找到一块足够放下对象的空间给对象实例,并更新列表的记录。(垃圾收集器用的是标记清理)
- 在分配内存的时候,肯定会有并发的问题,不管哪种都存在这种问题,要争抢内存。
- 解决并发问题的方法:1:CAS失败重试。2:本地线程分配缓冲,为了避免争抢,本地线程在堆中划一块自己专属的内存空间,本地线程只往自己的 内存空间中创建对象,默认是开启的,-XX:TLABSize 指定TLAB大小,不设置的话默认是Eden的百分之一。如果放不下就走cas。
3:初始化:给变量赋上默认值。类加载的时候会给静态变量赋上默认值。
4:设置对象头:
image-20230226145734134
对象头里边主要包含Mark Word结构(中间那个图32位的)
? 正常的对象,没有加锁的对象就是无锁态那一行,前25保存hashCode,后4为保存分代年龄<=15,后边3位保存锁的状态。
? Klass Pointer类型指针,一个对象new出来是在堆中,在这个对象头部区域有根指针指向元空间的类元信息,就是这个类型指针。比如 getClass,getMethod,getFileds… ….是通过这根指针找到的。
? 如果数组的话,会多出一块,存放数组长度占4个字节,只有数组才会有。
通过ClassLayout.parseInstance查看对象头
public static void main(String[] args) {
System.out.println("Object --- ");
ClassLayout layout = ClassLayout.parseInstance(new Object());
System.out.println(layout.toPrintable());
System.out.println("数组 --- ");
ClassLayout layout1 = ClassLayout.parseInstance(new int[]{});
System.out.println(layout1.toPrintable());
System.out.println("B对象 --- ");
ClassLayout layout2 = ClassLayout.parseInstance(new B());
System.out.println(layout2.toPrintable());
}
static class B {
int id;
String name;
byte aByte;
Object o;
}
输出结果为:
Object ---
java.lang.Object 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) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
数组 ---
[I 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) 6d 01 00 f8 (01101101 00000001 00000000 11111000) (-134217363)
12 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
16 0 int [I. N/A
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
B对象 ---
com.example.JvmModel.JvmTest$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) 65 cc 00 f8 (01100101 11001100 00000000 11111000) (-134165403)
12 4 int B.id 0
16 1 byte B.aByte 0
17 3 (alignment/padding gap)
20 4 java.lang.String B.name null
24 4 java.lang.Object B.o null
28 4 (loss due to the next object alignment)
Instance size: 32 bytes
Space losses: 3 bytes internal + 4 bytes external = 7 bytes total
Process finished with exit code 0
Instance size:为我们对象的大小。OFFSET:偏移量。SIZE:大小
我这电脑是64位,
Object内存:
前两行是Mark down 。
第三行是Klass Point,这是开启对象指针压缩,默认开启。没有开启的话,会由8个字节组成。。
最后一行是对齐。八个字节对齐,8的整数倍。是我们对象寻址效率最优的方式。
一个Object其实大小为12字节,但是为了要对齐8的整数倍,扩充4个字节,一个Object的大小为16个字节。
数组内存:
前两行依然是Mark down。
第三行是Klass Point。
第四行是数组的长度。
他的内存大小是16个字节,它不需要对齐。
B对象:
前三行… … markdown Klass Point
B.id:int占4个字节。
B.aByte:byte,占用一个字节。它的下一行是内存对齐,对齐成为4个字节。
B.name:String占用4个字节,存放的内存地址。这是开启对象指针压缩,默认开启。没有开启的话,会由8个字节组成。
B.o:对象占用4个字节,存放的内存地址。
最后一行对齐8。
5:执行init方法。将成员变量真正的赋值,然后还会调用对象的 构造方法。