java虚拟机中对象创建过程
java虚拟机中对象创建过程
我们平常创建一个对象,仅仅只是使用new关键字new一个对象,这样一个对象就被创建了,但是在我们使用new关键字创建对象的时候,在java虚拟机中一个对象是如何从无到有被创建的呢,我们接下来就来谈谈在java虚拟机中一个对象的创建过程(仅指我们平常使用的对象,不包括数组对象和Class对象)。
对象的内存布局
在了解对象的创建过程之前,我们先说说对象的内存布局,在HotSpot虚拟机中,对象在堆中的存储布局可以划分为三部分:对象头(Header)、示例数据(Instance Data)和对齐填充(Padding)。
对象头(Header)
HotSpot虚拟机对象的对象头包括两类信息。
第一类是用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等。
对象头的另一部分是类型指针,即对象指向它的类型元数据的指针,java虚拟机通过这个指针来确定该对象是哪个类的实例。
如果对象是一个Java数组,那在对象头中还必须有一块用于记录数组长度的数据,因为虚拟机可以通过普通Java对象的元数据信息确定Java对象的大小,但是如果数组的长度是不确定的,将无法通过元数据信息推断出数组的大小。
实例数据(Instance Data)
这部分是对象真正存储的有效信息,即我们在程序代码里面所定义的各种类型的字段内容,无论是从父类继承下来的,还是在子类中定义的自读那都必须记录起来。这部分的存储顺序会 受到虚拟机分配策略参数(-XX:FieldsAllocationStyle参数)和字段在Java源码中定义顺序的影响。 HotSpot虚拟机默认的分配顺序为longs/doubles、ints、shorts/chars、bytes/booleans、oops(Ordinary Object Pointers,OOPs)。
如果HotSpot虚拟机的 +XX:CompactFields参数值为true(默认就为true),那子类之中较窄的变量也允许插入父类变量的空 隙之中,以节省出一点点空间。
对齐填充(Padding)
这部分不是必须存在的,也没有特殊的意义,它仅仅起到占位符的作用。
由于HotSpot虚拟机的自动内存管理系统要求对象起始地址必须是8字节的整数倍,换句话说就是 任何对象的大小都必须是8字节的整数倍。对象头部分已经被精心设计成正好是8字节的倍数(1倍或者 2倍),因此,如果对象实例数据部分没有对齐的话,就需要通过对齐填充来补全。
对象的创建
当Java虚拟机遇到一条字节码new指令时,会首先去检查这个指令的参数是否能正常在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已经被加载、解析和初始化过。如果没有那必须先执行相应的类加载过程。类加载过程可以看这篇文章。
在类加载完成后对象所需的内存大小便已经确定,接下来就是给新对象在java堆中分配存储空间,这个过程相当于是将一块确定大小的内存块从java堆中划分出来,这个过程有两种方式:
-
指针碰撞
这种方式适用于Java堆中的内存空间是规整的情况,这种情况下被使用的内存在一边,空闲的空间在另一边,中间放着一个指针作为分界点的指示器,这种情况下分配内存就只是将中间的指针向空闲空间的方向移动一段与对象大小相等的距离即可。
-
空闲列标
这种方式适用于Java堆中的内存空间是不规整的情况,这种情况下适用过的内存和空闲的内存交错在一起,这样就不能使用简单的指针碰撞来给对象分配内存了。此时虚拟机维护了一个列表,记录了哪些内存块是可用的,在给对象分配内存时,从列表中找到一块足够大的空间划分给对象实例,并更新列表上的记录即可。
内存分配完成之后,虚拟机必须将分配到的内存空间(但不包括对象头)都初始化为零值。这步保证了对象的实例字段在Java代码可以不赋初值就直接使用,程序能访问到这些字段的数据类型所对应的零值。
接下来,Java虚拟机还要对对象进行必要的设置,例如这个对象是哪个类的实例、如何才能找到 类的元数据信息、对象的哈希码(实际上对象的哈希码会延后到真正调用Object::hashCode()方法时才 计算)、对象的GC分代年龄等信息。这些信息存放在对象的对象头(Object Header)之中。
在上面的工作完成之后,从虚拟机的角度来看,一个新的对象已经产生了。但是从Java程序的角度来看,对象的创建才刚刚开始,因为构造函数(即Class文件中的init方法)还没有执行,所有的字段都还是默认的零值。一般来说,new指令之后会接着执行 ()方法,按照程序员的意愿对对象进行初始化,这样一个真正可用的对象才算完全被构造出来。
对象的访问定位
创建对象自然是为了后续使用该对象,我们的Java程序会通过栈上的reference数据来操作堆上的具 体对象。对象的访问方式是由虚拟机实现而定的,主流的访问方式有使用句柄和直接指针两种。
句柄访问
如果使用句柄访问的话,Java堆中将可能会划分出一块内存来作为句柄池,reference中存储的就 是对象的句柄地址,而句柄中包含了对象实例数据与类型数据各自具体的地址信息。

直接指针
如果使用直接指针访问的话,Java堆中对象的内存布局就必须考虑如何放置访问类型数据的相关 信息,reference中存储的直接就是对象地址,如果只是访问对象本身的话,就不需要多一次间接访问 的开销。

这两种对象访问方式都各有优势,使用句柄访问的最大好处就是reference中存储的时稳定的句柄地址,在对象被移动时只会改变句柄中的实例数据指针,而reference本身不会被修改。
使用直接指针来访问最大的好处就是速度更快,它节省了一次指针定位的时间开销,由于对象访 问在Java中非常频繁,因此这类开销积少成多也是一项极为可观的执行成本。
相关文章:
java虚拟机中对象创建过程
java虚拟机中对象创建过程 我们平常创建一个对象,仅仅只是使用new关键字new一个对象,这样一个对象就被创建了,但是在我们使用new关键字创建对象的时候,在java虚拟机中一个对象是如何从无到有被创建的呢,我们接下来就来…...
3485. 最大异或和
Powered by:NEFU AB-IN Link 文章目录3485. 最大异或和题意思路代码3485. 最大异或和 题意 给定一个非负整数数列 a,初始长度为 N。 请在所有长度不超过 M的连续子数组中,找出子数组异或和的最大值。 子数组的异或和即为子数组中所有元素按位异或得到的…...
SpringBoot:SpringBoot配置文件.properties、.yml 和 .ymal(2)
SpringBoot配置文件1. 配置文件格式1.1 application.properties配置文件1.2 application.yml配置文件1.3 application.yaml配置文件1.4 三种配置文件优先级和区别2. yaml格式2.1 语法规则2.2 yaml书写2.2.1 字面量:单个的、不可拆分的值2.2.2 数组:一组按…...
QT 学习之QPA
QT 为实现支持多平台,实现如下类虚函数 Class Overview QPlatformIntegration QAbstractEventDispatcherQPlatformAccessibilityQPlatformBackingStoreQPlatformClipboardQPlatformCursorQPlatformDragQPlatformFontDatabaseQPlatformGraphicsBufferQPlatformInput…...
Pytorch中FLOPs和Params计算
文章目录一. 含义二. 使用thop库计算FLOPs和Params三. 注意四. 相关链接一. 含义 FLOPs(计算量):注意s小写,是floating point operations的缩写(这里的小s则表示复数),表示浮点运算数ÿ…...
DP1621国产LCD驱动芯片兼容替代HT1621B
目录DP1621简介DP1621芯片特性DP1621简介 DP1621是点阵式存储映射的LCD驱动器芯片,可支持最大128点(32SEG * 4COM)的 LCD屏,也支持2COM和3COM的LCD屏。单片机可通过3/4个通信脚配置显示参数和发送显示数据,也可通过指…...
Linux 用户管理
用户管理 useradd新增用户 格式:useradd [参数] 用户名称 常用参数: -c comment 指定一段注释性描述。 -d 目录 指定用户主目录,如果此目录不存在,则同时使用-m选项,可以创建主目录。 -g 用户组 指定用户所属的用户组…...
前端vue面试题(持续更新中)
vue-router中如何保护路由 分析 路由保护在应用开发过程中非常重要,几乎每个应用都要做各种路由权限管理,因此相当考察使用者基本功。 体验 全局守卫: const router createRouter({ ... }) router.beforeEach((to, from) > {// .…...
Java查漏补缺-从入门到精通汇总
Java查漏补缺(01)计算机的硬件与软件、软件相关介绍、计算机编程语言、Java语言概述、Java开发环境搭建、Java开发工具、注释、API文档、JVM Java查漏补缺(02)关键字、标识符、变量、基本数据类型介绍、基本数据类型变量间运算规…...
软件测试2年半的我,谈谈自己的理解...
软件测试两年半的我,谈谈自己的理解从2020年7月毕业,就成为一名测试仔。日子混了一鲲年,感觉需要好好梳理一下自己的职业道路了,回顾与总结下吧。一、测试的定位做事嘛,搞清楚自己的定位很重要。要搞清楚自己的定位&am…...
什么是SAS硬盘
什么是SAS硬盘SAS是新一代的SCSI技术,和Serial ATA(SATA)硬盘都是采用串行技术,以获得更高的传输速度,并通过缩短连结线改善内部空间等。SAS是并行SCSI接口之后开发出的全新接口。此接口的设计是为了改善存储系统的效能、可用性和扩充性&…...
一文理解服务端渲染SSR的原理,附实战基于vite和webpack打造React和Vue的SSR开发环境
SSR和CSR 首先,我们先要了解什么是SSR和CSR,SSR是服务端渲染,CSR是客户端渲染,服务端渲染是指 HTTP 服务器直接根据用户的请求,获取数据,生成完整的 HTML 页面返回给客户端(浏览器)展…...
Matlab 实用小函数汇总
文章目录Part.I 元胞相关Chap.I 创建空 char 型元胞Part.II 矩阵相关Chap.I 矩阵插入元素Part.III 字符串相关Chap.I 获取一个文件夹下所有文件的文件名的部分内容Part.IV 结构体相关Chap.I 读取结构体Chap.II 取结构体中某一字段的所有值本篇博文记录一些笔者使用 Matlab 时&a…...
Echarts 仪表盘倾斜一定角度显示,非中间对称
第024个点击查看专栏目录大多数的情况下,制作的仪表盘都是中规中矩,横向中间对称,但是生活中的汽车,摩托车等仪表盘确是要倾斜一定角度的,Echarts中我们就模拟一个带有倾斜角度的仪表盘。核心代码见示例源代码 文章目录…...
Vue中如何利用websocket实现实时通讯
首先我们可以先做一个简单的例子来学习一下简单的websocket模拟聊天对话的功能 原理很简单,有点像VUE中的EventBus,用emit和on传来传去 首先我们可以先去自己去用node搭建一个本地服务器 步骤如下 1.新建一个app.js,然后创建pagejson.js文…...
力扣解法汇总1144. 递减元素使数组呈锯齿状
目录链接: 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目: https://github.com/September26/java-algorithms 原题链接:力扣 描述: 给你一个整数数组 nums,每次 操作 会从中选择一个元素并 将该元素的…...
Spring彻头彻尾的讲解,按照Spring框架启动流程,逐步剖析问题,不再是大杂烩!
文章目录1. 定义Spring Bean篇1.1 定义Spring Bean的几种方式1.1.1 XML文件定义Spring Bean1.1.2 JavaConfig定义Spring Bean1.1.3 Component注解定义SpringBean1.2 装配Spring Bean的四种常用方式1.2.1 手动装配 XML文件1.2.2 自动装配 XML文件1.2.3 手动装配 JavaConfig文…...
[2]MyBatis+Spring+SpringMVC+SSM整合一套通关
二、Spring 1、Spring简介 1.1、Spring概述 官网地址:https://spring.io/ Spring 是最受欢迎的企业级 Java 应用程序开发框架,数以百万的来自世界各地的开发人员使用 Spring 框架来创建性能好、易于测试、可重用的代码。 Spring 框架是一个开源的 Jav…...
Javascript的API基本内容(三)
一、事件流 假设页面里有个div,当触发事件时,会经历两个阶段,分别是捕获阶段、冒泡阶段简单来说:捕获阶段是 从父到子 冒泡阶段是从子到父实际工作都是使用事件冒泡为主 二、页面加载事件 加载外部资源(如图片、外联CS…...
【Python入门第十九天】Python 函数
函数是一种仅在调用时运行的代码块。 可以将数据(称为参数)传递到函数中。 函数可以把数据作为结果返回。 创建函数 在 Python 中,使用 def 关键字定义函数: 实例 def my_function():print("Hello from a function&quo…...
如何通过 Pretty TypeScript Errors 提升开发效率:下载量激增背后的成功秘诀 [特殊字符]
如何通过 Pretty TypeScript Errors 提升开发效率:下载量激增背后的成功秘诀 🔥 【免费下载链接】pretty-ts-errors 🔵 Make TypeScript errors prettier and human-readable in VSCode 🎀 项目地址: https://gitcode.com/gh_mi…...
Data Storage and Computation
Data Storage and Computation 数据存储与计算假设一张表有 3 个字段:id BIGINT(8 字节 / 条) name VARCHAR(20)(实际平均 10 字节 / 条) age TINYINT(1 字节 / 条)单行实际数据占用࿱…...
Linux下Cursor AI编辑器自动化安装脚本设计与实现
1. 项目概述:为什么我们需要一个Cursor的Linux安装脚本如果你是一个在Linux环境下工作的开发者,并且对AI辅助编程工具感兴趣,那么Cursor这个名字你一定不陌生。作为一款集成了强大AI能力的代码编辑器,它正迅速成为许多程序员的新宠…...
Go语言单例模式如何实现_Go语言单例模式教程【通俗】
sync.Once是最安全的单例初始化方式,天然解决并发首次调用竞态问题,只执行一次闭包;须作包级或结构体字段,避免局部变量失效;panic后会持续失败,需自行兜底。Go 里 sync.Once 是最安全的单例初始化方式直接…...
“腾讯给 DeepSeek 出资 60 亿,占约 2% 股权。另一家巨头未入局”
最近 DeepSeek 首轮外部融资的消息,引发全网关注,各种消息满天飞咯。①在 5 月 9 日的「DeepSeek 和阿里谈崩了」留言区,就有读者提到“腾讯曾提出认购最多 20% 股份,但因比例过高被婉拒。”今天又刷到鹅厂出资信息的另外一个版本…...
如何设计完美的 TypeScript 错误消息模拟测试数据:深入理解 pretty-ts-errors 测试策略 [特殊字符]
如何设计完美的 TypeScript 错误消息模拟测试数据:深入理解 pretty-ts-errors 测试策略 🔍 【免费下载链接】pretty-ts-errors 🔵 Make TypeScript errors prettier and human-readable in VSCode 🎀 项目地址: https://gitcode…...
LynxPrompt Action:GitHub Actions 实现 AI 配置中心化与自动化管理
1. 项目概述:为什么我们需要一个AI配置的“中央仓库”? 如果你和我一样,日常开发中同时用着Cursor、Claude Code、GitHub Copilot,甚至还在尝试Windsurf和Aider,那你一定遇到过这个头疼的问题:每个工具的配…...
Arm嵌入式多线程编程:原理、实践与优化
1. Arm嵌入式开发中的多线程编程基础在嵌入式系统开发中,多线程编程是提高系统响应能力和资源利用率的重要手段。Arm架构作为嵌入式领域的主流处理器架构,其编译器工具链对多线程编程提供了完善的支持。不同于通用计算环境,嵌入式系统的多线程…...
InjectFix实战解析:在Unity IL2CPP环境下实现C#热修复的权衡与策略
1. InjectFix在IL2CPP环境下的核心价值 当你的Unity手游在应用商店上线后突然出现致命Bug,传统解决方案往往需要重新打包、提交审核、等待上架,这个过程可能耗时数天。而InjectFix提供的C#热修复能力,可以在不更新客户端的情况下快速修复线上…...
gogoclaw:基于文件与技能的自主智能体运行时设计与实践
1. 项目概述:一个以文件为基石的自主智能体运行时如果你和我一样,对市面上那些“黑盒”式的AI智能体框架感到厌倦,总觉得它们把太多逻辑和状态藏在运行时深处,调试和扩展起来像在拆盲盒,那么gogoclaw这个项目可能会让你…...
