前言
在java语言中永远绕不开的一个话题就是java对象,不管是面试,还是学习,了解对象的创建过程都是十分的有必要的。
对象的创建过程
首先,我们说的对象仅仅只是java的普通的对象,并不包括class对象和数组对象等等。对象的创建有很多种,我们这里说的仅仅是最常用的,用new关键字创建对象。
当我们使用new关键字创建对象的时候,虚拟机首先会去检查这个指令的参数是否能在常量池种定位到一个类符号的引用,并检查这个符号引用是否被加载和解析,初始化过。如果没有就必须先执行类的加载。
在类检查通过之后,接下来虚拟级将为新生对象分配内存,,分配内存的过程实际上就是把java堆中一个确定大小的内存划分出来。假如java堆内存绝对规整(使用的在一边,空闲的在另一边),这种分配就是java指针移动一个位置,就可以实现内存分配,这种的分配方式称为指针碰撞。
如果内存不规整,则需要有一个表专门记录,当给对对象分配内存时,就会更新这个表的记录,这种方式被称为空闲列表。
选择哪种分配方式,是由java内存堆是否规整决定的,而堆是否规整,又是有java采用的垃圾收集器是否带有空间压缩整理的能力决定的。
除了分配方式,java在分配内存的时候是线程不安全的。为了解决这个问题,有两种方案可供选择,一种是基于cas配上失败重试的方式保证更新的操作原子性,另一种是给每个线分配一小个分配缓冲区,哪个线程分配内存,就用对应的分配缓冲区。
然后再对象得到对应的内存之后,将对应的内存空间清零(不包括对象头的信息),以上就是java对象的创建过程。
对象的内存布局
对象在堆中的内存布局分为,对象头和实例数据和对齐填充三部分。
对象头是存储一些哈希码,锁标志,偏向线程id等等之类的信息,对象头是一个动态定义的数据结构,就是根据实际大小定义数据结构。实例数据则是对象要存储的真正信息如学生的名字,年龄等等。对齐填充不是必然存在的,任何对象的大小都必须是8字节的倍数,对其填充就是为了达成这个条件补全对象大小用的。
对象的访问定位
主要有两种方式,一种是句柄访问,一种是指针访问。句柄访问的话,reference种存储的是句柄的实例数据,访问对象还需要通过句柄池找到对象的指针,才能访问到对象的地址,多了一次开销。指针访问则是直接能够访问到对象的地址。
总结
对象的创建过程是极其复杂的,这里只是大概的介绍了下创建过程,其中很多的细节,并未在这里进行展开的介绍。最后i如果文章中有描述错误之处,欢迎指正。