《JVM从小白学成大佬》系列推出到现在,收到了很多小伙伴的好评,也收到了一些小伙伴的建议,在此表示感谢。

有几个小伙伴提出了希望出一篇介绍对象的创建及访问,猿人谷向来是没有原则的,小伙们要求啥,咱就尽力满足,毕竟文章就是对自己学习的一个总结及和各位小伙伴交流学习的机会。话不多说,直接开撸!

1 创建对象

在Java程序运行过程中无时无刻都有对象被创建出来,java中对象可以采用new或反射或clone或反序列化的方法创建。接下来我们我们介绍在虚拟机中,对象(限于普通Java对象,不包括数组和Class对象等)的创建过程。

字节码new表示创建对象,虚拟机遇到该指令时,从栈顶取得目标对象在常量池中的索引,接着定位到目标对象的类型。接下来,虚拟机将根据该类的状态,采取相应的内存分配技术,在内存中分配实例空间,并完成实例数据和对象头的初始化。这样,一个对象就在JVM中创建好了。

实例的创建过程,首先根据从类常量池中获取对象类型信息并验证类是否已被解析过,若确保该类已被加载和正确解析,使用快速分配(fast allocation)技术为该类分配对象空间;若该类尚未解析过,则只能通过慢速分配(slow allocation)方式分配实例对象。实例的创建流程如下图所示。

对象创建的基本流程:

  1. 验证类已被解析。
  2. 获取instanceKlass,确保Klass已完全初始化。
  3. 若满足快速分配条件,则进入快速分配流程。
  4. 若不满足快速分配条件,或者快速分配失败,则进入慢速分配流程。

1.1 快速分配

如果在实例分配之前已经完成了类型的解析,那么分配操作仅仅是在内存空间中划分可用内存,因此能以较高效率实现内存分配,这就是快速分配

根据分配空间是来自于线程私有区域还是共享的堆空间,快速分配可以分为两种空间选择策略。HotSpot通过线程局部分配缓存技术(Thread-Local Allocation Buffers,即TLABs)可以在线程私有区域实现空间的分配。

可以通过VM选项UseTLAB来开启或关闭TLAB功能。

根据是否使用TLAB,快速分配方式有两种选择策略:

  • 选择TLAB:首先尝试在TLAB中分配,因为TLAB是线程私有区域,故不需要加锁便能够确保线程安全。在分配一个新的对象空间时,将首先尝试在TLAB空间中分配对象空间,若分配空间的请求失败,则再尝试使用加锁机制在Eden区分配对象。
  • 选择Eden空间:若失败,则尝试在共享的Eden区进行分配,Eden区是所有线程共享区域,需要保证线程安全,故采用原子操作进行分配。若分配失败,则再次尝试该操作,直到分配成功为止。

实例空间分配成功以后,将对实例进行初始化。待完成对象的空间分配和初始化后,就可以设置栈顶对象引用。当然,对象的空间分配和初始化操作都是基于从类常量池中获取对象类型并确保该类已被加载和正确解析的前提下进行的,如果类未被解析,则需要进行慢速分配。

1.2 慢速分配

之所以成为慢速分配,正是因为在分配实例前需要对类进行解析,确保类及依赖类已得到正确的解析和初始化。慢速分配是调用InterpreterRuntime模块_new()进行的,实现代码如下。

// 确保要初始化的类不是抽象类型
klass->check_valid_for_instantiation(true, CHECK);
// 确保类已初始化
klass->initialize(CHECK);
// 分配实例
oop obj = klass->allocate_instance(CHECK);
// 在线程栈中设置对象引用
thread->set_vm_result(obj);

2 对象的访问定位

建立对象是为了使用对象,Java程序需要通过栈上的reference数据来操作上的具体对象。由于reference类型在Java虚拟机规范中只规定了一个指向对象的引用,并没有定义这个引用应该通过何种方式去定位、访问堆中的对象的具体位置,所以对象访问方式也是取决于虚拟机实现而定的。

目前主流的访问方式有使用句柄直接指针两种:

  • 如果使用句柄访问的话,那么Java堆中将会划分出一块内存来作为句柄池,reference中存储的就是对象的句柄地址,而句柄中包含了对象实例数据与类型数据各自的具体地址信息,如下图所示。

  • 如果使用直接指针访问,那么Java堆对象的布局中就必须考虑如何放置访问类型数据的相关信息,而reference中存储的直接就是对象地址。即使用直接指针访问在对象被移动时reference本身需要被修改,reference存储的就是对象地址。如下图所示。

这两种对象访问方式各有优势:

  • 使用句柄来访问的最大好处就是reference中存储的是稳定的句柄地址,在对象被移动(垃圾收集时移动对象时非常普遍的行为)时只会改变句柄中的实例数据指针,而reference本身不需要修改。
  • 使用直接指针访问方式的最大好处就是速度更快,它节省了一次指针定位的时间开销,由于对象的访问在Java中非常频繁,因此这类开销积少成多后也是一项非常可观的执行成本。

HotSpot就是使用第二种方式进行对象访问的,但从整个软件开发的范围来看,各种语言和框架使用句柄来访问的情况也十分常见。

【JVM从小白学成大佬】6.创建对象及对象的访问定位的更多相关文章

  1. 【JVM从小白学成大佬】3.深入解析强引用、软引用、弱引用、幻象引用

    关于强引用.软引用.弱引用.幻象引用的区别,在很多公司的面试题中经常出现,可能有些小伙伴觉得这个知识点比较冷门,但其实大家在开发中经常用到,如new一个对象的时候就是强引用的应用. 在java语言中, ...

  2. 【JVM从小白学成大佬】4.Java虚拟机何谓垃圾及垃圾回收算法

    在Java中内存是由虚拟机自动管理的,虚拟机在内存中划出一片区域,作为满足程序内存分配请求的空间.内存的创建仍然是由程序猿来显示指定的,但是对象的释放却对程序猿是透明的.就是解放了程序猿手动回收内存的 ...

  3. 【JVM从小白学成大佬】2.Java虚拟机运行时数据区

    目录 1.运行时数据区介绍 2.堆(Heap) 是否可能有两个对象共用一段内存的事故? 3.方法区(Method Area) 4.程序计数器(Program Counter Register) 5.虚 ...

  4. 【JVM从小白学成大佬】5.垃圾收集器及内存分配策略

    前面介绍了垃圾回收算法,接下来我们介绍垃圾收集器和内存分配的策略.有没有一种牛逼的收集器像银弹一样适配所有场景?很明显,不可能有,不然我也没必要单独搞一篇文章来介绍垃圾收集器了.熟悉不同收集器的优缺点 ...

  5. 【JVM从小白学成大佬】开篇

    JVM的重要性毋庸置疑,可以毫不夸张的说Java虚拟机是整个Java平台的基石. JVM方面的知识,也一直是BAT等大厂面试考核的重点.特别是JVM调优,故障排查性能调优,你知道该从哪些方面入手吗? ...

  6. jvm学习记录-对象的创建、对象的内存布局、对象的访问定位

    简述 今天继续写<深入理解java虚拟机>的对象创建的理解.这次和上次隔的时间有些长,是因为有些东西确实不好理解,就查阅各种资料,然后弄明白了才来做记录. (此文中所阐述的内容都是以Hot ...

  7. 【JVM之内存与垃圾回收篇】对象实例化内存布局与访问定位

    对象实例化内存布局与访问定位 从各自具体的内存分配上来讲 new 的对象放在堆中 对象所属的类型信息是放在方法区的 方法当中的局部变量放在栈空间 这 new 的对象怎么把三块粘合到一起 就是这章的内容 ...

  8. 【JVM第六篇--对象】对象的实例化、内存布局和访问定位

    写在前面的话:本文是在观看尚硅谷JVM教程后,整理的学习笔记.其观看地址如下:尚硅谷2020最新版宋红康JVM教程 一.对象的实例化 在平常写代码的过程中,我们用class关键字定义的类只是一个类的模 ...

  9. 【深入理解JVM】:Java对象的创建、内存布局、访问定位

    对象的创建 一个简单的创建对象语句Clazz instance = new Clazz();包含的主要过程包括了类加载检查.对象分配内存.并发处理.内存空间初始化.对象设置.执行ini方法等. 主要流 ...

随机推荐

  1. golang 任意类型之间相互转换

    在处理一些参数的时候,可能需要将参数转换为各种类型,这里实现一个通用的转换函数,实现各种类型之间的相互转换. 当然,如果源数据格式和目标数据类型不一致,是会返回错误的.例如将字符串“一二三”转换为数值 ...

  2. spring中获取容器中的Bean为什么前转成接口而不是实现类

    简单介绍一下上下文,userService是服务层接口有一个save方法,userServiceImpl是该接口的实现类重写了save方法. applicationContext.xml如图: 后台代 ...

  3. 《css的总结》

    一.span标签:能让某几个文字或者某个词语凸显出来 <p> 今天是11月份的<span>第一天</span>,地铁卡不打折了 </p> 二.字体风格 ...

  4. 使用.csv文件

    引用自:https://blog.csdn.net/vision_tung/article/details/79845758 通用爬虫:https://blog.csdn.net/Vision_Tun ...

  5. yum源使用报错

    CentOS系统yum源使用报错:Error: Cannot retrieve repository metadata (repomd.xml) for repository: rpmforge. 服 ...

  6. VM虚拟机Linux系统eth0下面没有inet和inet6

    今天打开虚拟机发现ip有问题,VM虚拟机Linux系统eth0下面没有inet和inet6,明明都是配置好的 打开任务管理器-> 服务-> 打开VM的nat和DHCP和hostd 正常后:

  7. shiro 和 spring boot 的集成

    1 添加依赖 使用 shiro-spring-boot-web-starter 在 spring boot 中集成 shiro 只需要再添加一个依赖 <dependency> <gr ...

  8. Drools规则引擎-如果判断某个对象中的集合是否包含指定的值

    规则引擎集合相关处理 在实际生产过程中,有很多关于集合的处理场景,比如一个Fact对象中包含有一个集合,而需要判断该集合是否包含某个值.而Drools规则引擎也提供了多种处理方式,比如通过from.c ...

  9. 【Android】SDK Manager 设置代理

    这里是 Mac 系统下,Windows 环境类似.打开 Android SDK Manager, Proxy Settings 设置如下所示: PS: 注意勾选 "Force https:/ ...

  10. 电信光猫带路由器(F452)的虚拟服务器端口映射

    现在电信宽带的光猫一般都自带路由器功能,为了方便运营商管理网络用户,电信公司插入了企业局域网,网络用户的光猫路由器都是这个局域网的节点.用户家里的电脑在网络中的结构位置一般如下所示: 互联网(公网)= ...