一、Java对象创建过程
1、类加载检查
检查内容:类是否在常量池中有符号引用;检查这个类的符号引用是否被加载过;
2、分配内存
从java堆中获取指定大小内存分配给对象。分配方式有两种:指针碰撞、空闲列表,选择哪种方式由堆空间是否规整决定,而是否规整主要取决于垃圾回收算法是否有压缩整理的机制来决定。
指针碰撞:属于垃圾回收后内存规整的方式,垃圾回收规整的算法有:标记-整理和复制算法。将占用的内存放到一边,没有用的内存放到一边,在分配内存的时候,按空闲内存的指针直接获取指定大小的内存既可。通常垃圾回收方式有:串行垃圾回收算法(serial)、并行(parNew)
空闲列表:适用于堆内存不规整的情况。内存中维护了一个空闲列表,并标出每个空闲区域的大小,那么在申请内存时,可以找到空闲列表,并找到大小合适的内存空间分配给对象。最后更新空闲列表。同垃圾回收方式:CMS
内存分配的并发问题:CAS自旋方式。
3、初始化零值
将分配到内存空间的都初始化为零值,保证对象实例字段在java代码中可以不赋初始值就可以直接使用。
4、设置对象头
虚拟机对对象进行必要的设置,对对象头进行设置,这个对象是哪个类的实例,如何找到类的元数据信息,对象的哈希码,对象的GC分代年龄,还会根据虚拟机的配置设置偏向锁。
5、执行init方法
程序真正初始化的内容。
二、对应类加载过程:
加载:将文件加载到内存的过程
验证:验证文件的格式是否合法
准备:设置类变量初始值阶段
解析:将符号变量改为引用变量
初始化:执行init方法
三、对象在内存的保存形式:
对象头:
1、存储对象自身运行数据如哈希码、GC分代年龄、锁状态等信息
2、类型指正,指向这个对象的类。
实例数据:对象数据
对齐填充:无实际意义,只是为了保证JVM内存分配的原则,是8个字节。
四、对象的访问方式:
句柄:
java本地线程中的变量表中,保存了对象的reference;java堆中维护了句柄池;reference指向的就是java堆中的句柄池,句柄池的内容是:对象实例的指正、对象类型数据的指针。所以句柄的方式在访问数据的时候会有两次数据定位。
直接指针:
java本地线程中的变量中,保存了对象的reference,直接指向java堆中保存的对象数据,只不过堆中保存的对象数据中有对象的类型数据的指针,可以通过这个指针找到对象的类。
五、如何判断对象是无效对象?
1、引用计数法,为每个对象添加一个计数器,如果有对象使用就加1,应用结束就减1。对应的引用数量为0的时候,就表示该对象没有被应用,可以被垃圾回收。但是,如果两个对象之间是互相引用,那么就会导致对象永远不会被回收。无法解决循环引用问题。
2、可达性分析算法
通过GCRoot作为对象的起点,然后向下遍历,节点所走过的路径为引用链,当一个对象到GCRoot没有任何引用链相连,就认为这个对象是无效对象,可以被垃圾回收。
可以作为GCRoot的对象:
(1)、虚拟机栈中引用的对象;(方法内部引用的对象)
(2)、方法区中的类静态属性引用的对象;(类中定义的静态变量)
(3)、方法区中常量引用的对象;(对象中定义的变量)
(4)、本地方法栈中引用的对象;