jvm-------JAVA对象的创建过程/对象如何定位

目录

  • 推荐公众号
  • 参考书籍
  • JAVA对象的创建过程
  • 对象如何定位

推荐公众号

有彩蛋哦!!!(或者公众号内点击网赚获取彩蛋)
程序员探索之路

参考书籍

深入理解Java虚拟机 第二版 周志明著

JAVA对象的创建过程

Java是一门面向对象的语言,java程序运行过程中无时无刻都有对象被创建出来。在java代码实现层面克隆,反射,new关键字都可以实现,但是对于JVM而言是这样的:

jvm遇到一条new指令,首先去检查这个指令的参数能否在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已经被加载,解析和初始化。如果没有,那么先执行类的初始化。
检查完类加载后,jvm为对象分配内存。对象所需的内存大小在类加载完成之后就知道了,分配内存不过是在java堆中划分一块确定大小的内存。
2.1如果内存是规整的,那么jvm采用的是指针碰撞法来为对象分配内存。什么是指针碰撞法呢?首先内存是规整的也就是说用过的内存在一边,空闲的内存在一边,中间放着一个指针作为分界点的指示器,分配内存就是将指针向空闲内存的那一边挪动与对象大小相等的距离。

2.2如果内存不是规整的,也就是说已经使用和空闲内存交织在一起,那么jvm将采用空闲列表法来为对象分配内存。什么是空闲列表法呢?当内存不是规整的,那么jvm就不得不维护一个内存列表,用来记录那些内存是空闲的,哪些是已经使用了。为对象分配内存时,就从列表中找到一块足够大的空间分配各对象并更新列表。

什么时候使用指针碰撞法,什么时候使用空闲列表法呢?这和垃圾收集器有关,什么意思呢,垃圾收集器如果使用的是复制算法/标记-整理,那么内存就是规整的,那么就使用指针碰撞法;如果使用的标记-清除,那么内存就是不规整的,那么就使用空闲列表法。

3.对象分配空间时的线程安全问题。为什么分配对象的时候会有线程安全问题,比如说现在要创建一个A对象,采用指针碰撞法,正在分配但是还没有来得及修改指针位置,此时又要创建对象B,那么还是用的原来的指针来分配内存,所以会出现问题。

解决方案:

3.1 jvm采用CAS+失败重试保证更新操作的原子性

3.2 采用TLAB方式,什么是TLAB,就是为每一个线程分配一块内存区域,每个线程创建对象时都在各自的区域内存分配空间。

4.内存分配结束后,jvm将分配到的内存空间都初始化为零(不包括对象头)。这一步保证了对象实例可以不用赋值就可以直接使用,程序能访问到的字段的数据类型所对应的零值。

5.进行对象的必要设置,对象的哈希码,GC分代年龄,哪个类的实例等

6.执行方法,把对象按照程序员的意愿进行初始化,这样一个可以使用的对象才算产生出来。

对象如何定位

创建实例是为了使用它,那么怎么找到创建好的实例呢?

比如 Object obj = new Object(); 我们都知道实例包含类数据(实例是哪个类的等信息,存储在方法区中)和实例数据,obj 指向的是 具体的内存地址,但是JVM具体是怎么找到的呢?有两种实现方式:

句柄访问。Java堆中划分出一块句柄池,obj指向的是对象的句柄地址,句柄中包含了类数据地址和实例数据地址,这样做有什么好处呢,我们都知道会整理内存的GC算法需要改变对象的内存地址,如果使用句柄访问方式时只需要改变句柄池中执行的实例地址就行了;缺点是查找起来慢。
指针访问。Obj直接指向,实例数据地址和类数据地址。好处:快速访问;缺点在整理内存时,需要改变obj的指向。HotSpot采用的指针访问的方式。

你可能感兴趣的:(jvm)