2.对象的创建
从.java文件经过编译之后生成.class字节码文件,而字节码文件由虚拟机解释运行通常有以下步骤
伴随着这样一个流程,可以知道对象的创建是发生在初始化之后和使用之前。
对象的创建
虚拟机遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载,解析和初始化过。
在类加载检查通过后,接下来虚拟机将为新生对象分配内存。对象所需要的内存大小已经在类加载完成后便可以完全确定,为对象分配空间的认为等同于把一块确定大小的内存从Java堆中划分出来。
在Java堆内存规整的情况下,对象内存分配是将临界指针往空闲部分的内存区偏移新生对象大小的距离。
若Java堆内存并非规整,虚拟机维护一个列表,记录哪些内存块是可用的,在分配的时候找到一块足够大的内存空间划分给对象实例,并更新列表上的记录。这种分配方式称为“空闲列表”。
决定哪种分配方式是由Java堆决定的,而Java堆是否规整又由所采用的垃圾收集器是否带有压缩整理功能决定的。
对象的内存布局
对象在内存中存储的布局可以分为3块区域:对象头(Header),实例数据(Instance Data)和对齐填充(Padding) 对象头包括两部分信息,第一部分用于存储自身的运行时数据,如哈希码,GC分代龄,锁状态标志,线程持有的锁,偏向线程的ID,偏向时间戳等。第二部分是类型指针,即对象指向它的类元数据的指针。
实例数据是对象真正存储的有效信息,这部分的存储顺序会受到虚拟机分配策略和字段在Java源码中定义的顺序的影响。
对齐填充并不是必然存在的,也没有特别的含义,它仅仅起着占位符的作用。
对象的访问定位
目前主流的访问方式有使用句柄和直接指针的两种方式。
使用句柄访问
定义: Java堆中将会划分出一块内存来作为句柄池,refenerce中存储的就是对象的句柄的地址,而句柄中包 含了对象实例数据与类型数据各自的具体地址信息
优点 : 最大的好处就是reference中存储的是稳定的句柄的地址,在对象被移动(垃圾回收时移动对象是很常见的行为)时只会改变句柄中的实例数据的地址,而reference本身不需要修改
直接指针
定义 : reference中存储直接对象的地址,但是必须考虑放置访问类型数据的相关信息
优点 : 访问速度快,节省了一次指针定位的时间开销
欢迎关注公众号lanxue-it获取更多猛料干货