JVM--基础--20--对象的创建过程

2023-11-10

JVM–基础–20–对象的创建过程


1、对象的创建过程

  1. 讨论的对象限于普通Java对象,不包括数组和Class对象等。
  2. 虚拟机遇到一条new指令时:过程如下

1.1、类加载

当虚拟机遇到一条new指令时 ,首先去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已经被加载、解析和初始化过,如果没有,那必须先执行相应的类加载过程。

1.2、内存分配

当已经执行过类加载过程后,会为新对象在Java堆中分配一块大小已经确定(类加载后确定)的内存,具体的内存分配规则有以下两种

1.2.1、指针碰撞(Bump the Pointer)

如果Java堆中的内存是绝对规整的,所有用过的内存放一边,空闲的内存放到一边,中间放着指针为分界点,分配内存就是把指针向空闲的一边挪动一段与对象大小相等的距离。

1.2.2、空闲列表(Free List)

如果Java堆中的内存并不是规整对的,已使用的内存和空间相互交错,虚拟机会将可以用的内存维护到一个列表上,在分配内存时从这个列表中找到一块足够大的空间划给对象。然后更新列表记录(将对应的这个记录在列表中删去)。

1.2.3、扩展

1. 内存分配方式由Java堆是否规则来决定 --》Java堆中是否规整是根据虚拟机所采用的垃圾收集器是否带有压缩整理功能决定的。
2. Serial、ParNew带压缩整理的收集器用指针碰撞。
3. CMS这种基于mark-sweep算法的收集器通常用空闲列表。

1.3、防止并发

在虚拟机上创建对象是非常频繁的行为,所以要做到防止并发,有以下两种方式可实现:

  1. 对分配内存空间的动作进行同步处理,实际上JVM采用CAS(Cmpare And Set)配上失败重试的方式保证更新操作的原子性;
  2. 把内存分配的动作按照线程划分在不同的空间之中进行,即为每个线程在java堆中预先分配一块小内存,称为本地线程分配缓冲区(Thread Local Allocation Buffer,TLAB)。分配内存时在线程的TLBA上分配,只有TLAB用完并分配新的TLAB时,才需要同步锁定。JVM是否使用TLAB可以通过-XX:+UseTLAB参数来设定。

1.4、初始化对象内存空间(换个说法就是:为对象的所有字段附默认值)

内存分配完成后,JVM将分配到的内存空间都初始化为零值(不包括对象头),如果使用TLAB,这一过程可提前到TLAB分配时进行。

1.5、对象头的设置

将对象的类、哈希码、对象的GC分代年龄等信息设置到对象头之中。

1.5.1、执行Java的init方法(换个说法就是:执行构造方法)

设置完对象头后,从JVM的角度来看一个对象已经完成了,但是从java程序的角度来看还没有创建完成呢。此时就需要执行init方法,调用构造方法,这样一个真正可用的对象才算完全的产生出来。

下面代码是HotSpot虚拟机bytecodeInterpreter.cpp中的代码片段(这个解释器实现很少机会实际使用,大部分平台上都使用模板 解释器;当代码通过JIT编译器执行时差异就更大了。不过这段代码用于了解HotSpot的运作过程是没有什么问题的)。

// 确保常量池中存放的是已解释的类
    if (!constants->tag_at(index).is_unresolved_klass()) {
      // 断言确保是klassOop和instanceKlassOop(这部分下一节介绍)
      oop entry = (klassOop) *constants->obj_at_addr(index);
      assert(entry->is_klass(), "Should be resolved klass");
      klassOop k_entry = (klassOop) entry;
      assert(k_entry->klass_part()->oop_is_instance(), "Should be instanceKlass");
      instanceKlass* ik = (instanceKlass*) k_entry->klass_part();
      // 确保对象所属类型已经经过初始化阶段
      if ( ik->is_initialized() && ik->can_be_fastpath_allocated() ) {
        // 取对象长度
        size_t obj_size = ik->size_helper();
        oop result = NULL;
        // 记录是否需要将对象所有字段置零值
        bool need_zero = !ZeroTLAB;
        // 是否在TLAB中分配对象
        if (UseTLAB) {
          result = (oop) THREAD->tlab().allocate(obj_size);
        }
        if (result == NULL) {
          need_zero = true;
          // 直接在eden中分配对象
    retry:
          HeapWord* compare_to = *Universe::heap()->top_addr();
          HeapWord* new_top = compare_to + obj_size;
          // cmpxchg是x86中的CAS指令,这里是一个C++方法,通过CAS方式分配空间,并发失败的话,转到retry中重试直至成功分配为止
          if (new_top <= *Universe::heap()->end_addr()) {
            if (Atomic::cmpxchg_ptr(new_top, Universe::heap()->top_addr(), compare_to) != compare_to) {
              goto retry;
            }
            result = (oop) compare_to;
          }
        }
        if (result != NULL) {
          // 如果需要,为对象初始化零值
          if (need_zero ) {
            HeapWord* to_zero = (HeapWord*) result + sizeof(oopDesc) / oopSize;
            obj_size -= sizeof(oopDesc) / oopSize;
            if (obj_size > 0 ) {
              memset(to_zero, 0, obj_size * HeapWordSize);
            }
          }
          // 根据是否启用偏向锁,设置对象头信息
          if (UseBiasedLocking) {
            result->set_mark(ik->prototype_header());
          } else {
            result->set_mark(markOopDesc::prototype());
          }
          result->set_klass_gap(0);
          result->set_klass(k_entry);
          // 将对象引用入栈,继续执行下一条指令
          SET_STACK_OBJECT(result, 0);
          UPDATE_PC_AND_TOS_AND_CONTINUE(3, 1);
        }
      }
    }​
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JVM--基础--20--对象的创建过程 的相关文章

  • 来自行号的方法名称

    给定特定类源代码 Java C 的行号 是否有一种简单的方法来获取它所属的方法的名称 如果它落入其中 大概使用抽象语法树 这对于将 checkstyle 的输出限制为仅触及的方法很有用 我假设您必须使用抽象语法树来执行 Line gt Me
  • Java 错误和警告列表

    在哪里 如何获得所有 java 和 javac 的错误和警告消息的列表 This http mindprod com jgloss compileerrormessages html我认为页面是您所需要的
  • JAX-WS 入门 [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 有人可以推荐一些关于 JAX WS 入门的好教程吗 使用各种工具 如 wsgen 等 您可以从这里开始 通过 Java SE 6 平台介绍
  • Android Studio 与 Google Play 服务的编译问题

    我正在运行 Android Studio 0 8 4 并在 Android Studio 0 8 2 上尝试过此操作 我正在运行 Java JDK 1 8 0 11 并尝试使用 JDK 1 8 0 05 每当我尝试构建我的 android
  • 清空变量不会使方法引用无效[重复]

    这个问题在这里已经有答案了 为什么代码不抛出NullPointerException当我使用与变量绑定的方法引用时dog我后来分配了null to 我正在使用 Java 8 import java util function Functio
  • Spring 从 JBoss 上下文加载 PropertySourcesPlaceholderConfigurer

    我有一个使用 PropertySourcesPlaceholderConfigurer 的 spring 3 1 应用程序加载设置 我想管理测试和生产环境 只需从服务器上下文加载设置覆盖本地文件属性中指定的设置 下一个示例在 Tomcat
  • Google 表格使用 API 密钥而不是 client_secret.json

    In the QuickStart java示例Java 快速入门 https developers google com sheets api quickstart java他们使用OAuth client ID识别该应用程序 这会弹出一
  • 是否可以创建 Java RAM 磁盘以与 java.io.* API 一起使用?

    我正在使用一个第三方库 它基本上创建一个输出目录 其中包含不同类型的文件和子目录 我希望能够编写单元测试来确认输出正确 我希望能够将库与 RAM 磁盘一起使用 这样库所做的任何事情都不会以任何方式接触实际的磁盘板 这个想法是让测试运行和清理
  • 如何获取 JDBC 中 UPDATE 查询影响的所有行?

    我有一项任务需要使用更新记录PreparedStatement 一旦记录被更新 我们知道更新查询返回计数 即受影响的行数 但是 我想要的不是计数 而是受更新查询影响的行作为响应 或者至少是受影响的行的 id 值列表 这是我的更新查询 UPD
  • 始终将双精度舍入

    我怎么总是能把一个double to an int 并且永远不要将其四舍五入 我知道Math round double 但我希望它始终向上舍入 所以如果是的话3 2 四舍五入为 4 您可以使用Math ceil method 请参阅Java
  • javadoc 子集/java 库组织

    我自己从来没有运行过javadoc 无论是在命令行还是ant 的 javadoc 任务 http ant apache org manual Tasks javadoc html 我将使用 ant 我需要为我编写的库生成 javadoc 问
  • 在 Kotlin 中声明静态属性?

    My Java code public class Common public static ModelPengguna currentModelPengguna public class Common companion object v
  • 添加 char 和 int

    据我了解 字符是一个字符 即一个字母 一个digit 标点符号 制表符 空格或类似的东西 因此 当我这样做时 char c 1 System out println c 输出 1 正是我所期望的 那么为什么当我这样做时 int a 1 ch
  • 如何使用 AffineTransform.quadrantRotate 旋转位图?

    我想旋转一个bitmap关于它的中心点 然后将其绘制成更大的图形上下文 位图是40x40 pixels 图形上下文是500x500 pixels 这就是我正在做的 BufferedImage bi new BufferedImage 500
  • log4j.properties 在 Wildfly 上无法正常工作

    我的类路径中有一个 log4j properties 文件 它位于 APP XX jar log4j properties 位置 我注意到在ear文件中我还可以在lib文件夹中找到log4j 1 2 17 jar 但无论我在 log4j p
  • 难以理解 通配符

    我有一个非常基本的问题 下面的代码无法编译 假设 Apple Extends Fruit List
  • Spring MVC:通用 DAO 和服务类

    我正在 Spring MVC 中编写网页 我使用 Generic DAO 编写了所有 DAO 现在我想重写我的服务类 我该如何写 通用服务 我的 DAO 如下 DAO package net example com dao import j
  • 用于生成 ISO 文件的 Maven 插件

    有没有可以生成ISO镜像的maven插件 我需要获取一些模块的输出 主要是包含 jar 的 zip 文件 并将它们组合成一个 ISO 映像 Thanks 现在有一个 ISO9660 maven 插件可以完成这项工作 https github
  • Axis2 的 wsdl2java 在 RPC/Encoded 样式 Web 服务上失败

    Axis2 有替代方案吗 或者让它工作的方式 例如不同的数据绑定 Retrieving document at Exception in thread main org apache axis2 wsdl codegen CodeGener
  • Graphics2D setfont() 严重减慢了 java 应用程序的启动速度

    我正在用java制作一个游戏 它每秒刷新60次 每次执行循环时 我都会使用 g2d 来绘制图像和字符串 如果我这样做的话一切都会很好g2d setFont new Font Arial Font PLAIN 8 和抽绳 这将是正常的 但如果

随机推荐

  • 利用Github搭建自己专属博客

    这是一个在Windows简易的搭建博客的方法 建立使用Jekyll构建自己的博客 所以这一篇文章采用fork别人的模板来构建 偷懒 在此之前需要满足一下条件 注册一个Github账号 本地安装Git 并且能实现Git向自己的仓库push文件
  • minikube 实战篇 - 镜像打包部署 - 1

    实战篇 镜像打包 如果你是一个JAVA开发人员 需要把spring项目部署到minikube中 该怎么操作是一个需要探索的问题 这篇文章会讲解如何打包部署项目 1 生成demo项目 在浏览器端输入https start spring io
  • 第9章 Stata聚类分析

    目录 9 1划分聚类分析 1 数标准化处理 2 K个平均数的聚类分析 3 K个中位数的聚类分析 案例延伸 1 采用其他相异性指标 2 设置聚类变量的名称 3 设置观测样本为初始聚类中心 4 排除作为初始聚类中心的观测样本 9 2层次聚类分析
  • gdb 常用命令

    run r 运行 运行带参数的可执行文件 r 后面接参数 例如 gdb executablefile gdb r arg1 arg2 arg3 continue c 继续运行 next n 单步运行 step s 如果有函数则进入函数执行
  • Python 列表推导式、矩阵、格式化输出

    列表推导式 列表推导式提供了从列表 元组创建列表的简单途径 语法 表达式 for语句 if语句 创建并返回一个列表 if语句可选 示例 list1 1 2 3 4 使用元组也行 list2 x 2 for x in list1 print
  • Node.js 学习系列(四)—— 回调函数

    Node js 异步编程的直接体现就是回调 异步编程依托于回调来实现 但不能说使用了回调后程序就异步化了 回调函数在任务完成后就会被调用 Node 使用了大量的回调函数 Node 的所有 API 都支持回调函数 例如 我们可以一边读取文件
  • 【干货】dockerfastdfs集群

    正文 最近整理了一份 Netty 相关的文档干货 讲解很系统 今天分享给大家 看完这份文档你将获得哪些收获 理解当下火热的 Netty 框架 核心概念 开发流程 手写 RPC 框架 聊天室 Tomcat等 对照知识点进行查漏补缺 帮助扫除知
  • 类 AudioInputStream 说明文档 中文版

    javax sound sampled 类 AudioInputStreamjava lang Object java io InputStream javax sound sampled AudioInputStream 所有已实现的接口
  • angular 整理

    文章目录 网址 npm 知识点 参考 https www cnblogs com wjw1014 p 10262309 html 网址 angular https angular cn docs ag grid https www ag g
  • RHEL6.4启动一直在加载界面,无法进入图形化界面的解决办法

    在下在上午的时候将我另一个机器上面的虚拟机拷贝到了我现在用的机器上 发现rhel6 4启动加载的时候一直开在这个界面 如图 就一直卡在这个界面了 我用ctrl shift f1一看 哎 有点迷 咋回事啊 为了验证 我将我原来的机器也打开看了
  • 猪齿鱼平台的部署教程

    以下是基于猪齿鱼平台的部署教程 安装 Docker 在猪齿鱼平台中 应用会运行在 Docker 容器中 所以首先需要安装 Docker 可以按照以下步骤在 CentOS 7 系统上安装 Docker 安装依赖 sudo yum instal
  • kong认证插件添加第二认证方式

    在认证插件对象 如ldap auth 的anonymous 字段添加第二认证方式 查看ldap的插件设置 anonymous 为basic auth的plugin的consumer id 在Authorization中设置认证密码 user
  • vulnhub-sick0s1.2简单靶场提权

    以下均在测试环境进行 遵纪守法 靶场下载地址 https download vulnhub com sickos sick0s1 2 zip 下载后直接用vm导入 网卡NAT模式即可 首先进行信息收集 nmap 192 168 111 0
  • 500报错及故障排除

    500 Internal Server Error 每次打开网页时 浏览器都会向托管站点的服务器发送请求 服务器将返回请求的数据和响应代码 HTTP响应状态代码指示请求是否成功 500到599范围内的代码表示服务器错误 该错误不是由浏览器或
  • 论文英文参考文献[10]的时候后面多空格_毕业论文格式问题批量修改

    今天 给大家介绍一下毕业论文中常见的格式错误批量修改方法 问题一 英文摘要部分或参考文献的英文标点符号检查 采用ENDNOTE ZOTERO这类文献管理软件直接导入的 不存在这类问题 主要针对不会使用软件的而手动复制编写的参考文献 主要涉及
  • Mysql视图

    文章目录 1 简介 2 视图的操作语法 3 视图检查选项 4 视图的更新与作用 1 简介 视图 view 是一种虚拟存在的表 视图中的数据并不在数据库中实际存在 行和列数据来自定义视图的查询中使用的表 并且是在使用视图时动态生成的 通俗来讲
  • 缺页中断过程详解

    缺页中断机构 总而言之 对于我们的缺页的访问 会发生一个缺页中断 缺页中断由当前指令发出 所以属于内中断 中断后该程序就阻塞了 然后等待中断程序结束 再执行 中断程序判断 内存中是否有空闲内存块 如果有 就调入该内存块 并且修改页表项 如果
  • 【thinkphp5】使用tp5开发api接口 定义全局异常处理

    1 新建文件夹以及文件 路径 application lib exception ExceptionHandler php 并键入以下代码
  • Eigen库Vector3d定义及赋值学习

    include
  • JVM--基础--20--对象的创建过程

    JVM 基础 20 对象的创建过程 1 对象的创建过程 讨论的对象限于普通Java对象 不包括数组和Class对象等 虚拟机遇到一条new指令时 过程如下 1 1 类加载 当虚拟机遇到一条new指令时 首先去检查这个指令的参数是否能在常量池