半个读书笔记,没什么技术含量
从虚拟机的角度看创建对象
创建对象步骤:
1、虚拟机遇到new指令时,先进性类加载检查(即指令中的参数能否在常量池中定位,定位的符号引用的类是否已经被加载,解析,初始化),如果检查不通过,则需要先进行类加载的过程。
2、为对象分配内存空间,这里有两种方式:指针碰撞方式(当java堆绝对规整时)(直接移动指针),空闲列表方式(java堆不绝对规整时)(虚拟机自己维护一个空闲内存表,按表分配)。其中java堆是否规整又取决于虚拟机使用的GC算法。
值得一提的是,为对象分配空间的时候是存在线程安全问题的,针对这个虚拟机又有两个方案:第一个是CAS+失败重试方式,说白了就是乐观锁。第二种是TLAB方式,预算为每个线程分配一块内存,称为TLAB,分配内存时优先在这个区域里分配,不够的话再使用第一种分配方式。
3、将分配的内存空间初始化,把域什么的都置成默认初始值。
4、设置对象头
5、执行<init>
方法,按照程序逻辑来初始化(我理解的就是调用构造方法了)
对象结构
1、对象头:包括两部分:
①、存储对象自身运行时的数据:hashcode,GC分代年龄,锁状态标志,线程持有的锁,偏向线程id,偏向时间戳等。
②、类型指针,指向类元数据,确定对象是哪个类的实例。
java数组还需要在对象头记录数组长度
2、实例数据
3、对其填充:因为对象大小必须是8字节的整数倍,所以不符合的条件的对象需要进行填充以达到要求,没什么用。
对象访问定位
通过栈上的reference数据访问对象,有两种访问方式:
1、句柄访问:
reference -> 句柄 -> 实例数据
‘’‘’‘’‘’‘’‘’‘’‘’‘’‘’‘’‘’‘’‘’‘’‘’‘’‘ -> 类型数据
句柄记录地址
2、直接指针访问:
reference -> 实例数据
‘’‘’‘’‘’‘’‘’‘’‘’‘’‘’‘’‘’‘’类型数据指针 -> 类型数据
句柄访问方式修改地址方便,直接改指针指向就行
直接指针访问速度更快